1. redux & react-redux & redux-saga 등 설치
$ yarn add react-router-dom
$ yarn add redux react-redux redux-saga
$ yarn add @reduxjs/toolkit query-string axios
$ yarn add ramda
2. 주요소스
2.1 index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import { BrowserRouter as Router } from "react-router-dom";
import { Provider } from 'react-redux';
import store from '~/store'
import App from '~/App'
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<Provider store={store}>
<Router>
<App />
</Router>
</Provider>
);
2.2. reducer 설정
import { configureStore } from "@reduxjs/toolkit";
import rootReducer from "~/store/slices/rootReducer";
const initialState = {};
const store = configureStore({
reducer: rootReducer,
devTools: true,
preloadedState: initialState,
});
export default store;
import { combineReducers } from 'redux';
import { authReducer } from '~/store/slices/authSlice';
const rootReducer = combineReducers({
authReducer
});
export default rootReducer;
2.3. App.js
import React from 'react';
import RootRoutes from '~/routes';
const App = () => {
return (
<React.Suspense>
<RootRoutes />
</React.Suspense>
);
}
export default App;
2.4 react-router
// This is a React Router v6 app
import { Routes, Route, Navigate } from "react-router-dom";
import Login from '~/views/Login';
import PublicRoute from './PublicRoute';
const RootRoutes = () => (
<Routes>
<Route element={<PublicRoute />}>
<Route path="/login/" element={<Login />} />
</Route>
</Routes>
)
export default RootRoutes;
2.5 Login.js
import React from 'react';
import { useNavigate } from 'react-router-dom';
import { useDispatch } from 'react-redux';
import { useForm } from 'react-hook-form';
import Avatar from '@mui/material/Avatar';
import Button from '@mui/material/Button';
import TextField from '@mui/material/TextField';
import FormControlLabel from '@mui/material/FormControlLabel';
import Checkbox from '@mui/material/Checkbox';
import Link from '@mui/material/Link';
import Grid from '@mui/material/Grid';
import Box from '@mui/material/Box';
import LockOutlinedIcon from '@mui/icons-material/LockOutlined';
import Typography from '@mui/material/Typography';
import { setRefreshToken } from '~/utils/Cookie';
import { loginUser } from '~/api/Users';
function Copyright(props) {
return (
<Typography variant="body2" color="text.secondary" align="center" {...props}>
{'Copyright © '}
<Link color="inherit" href="https://github.com/dchkang83">
Your Website
</Link>{' '}
{new Date().getFullYear()}
{'.'}
</Typography>
);
}
function Login() {
const navigate = useNavigate();
const dispatch = useDispatch();
// useForm 사용을 위한 선언
const { register, setValue, formState: { errors }, handleSubmit } = useForm();
return (
<>
<Box
sx={{
marginTop: 8,
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
}}
>
<Avatar sx={{ m: 1, bgcolor: 'secondary.main' }}>
<LockOutlinedIcon />
</Avatar>
<Typography component="h1" variant="h5">
Sign in
</Typography>
<Box component="form" noValidate sx={{ mt: 1 }}>
<TextField
{...register("username", { required: "Please Enter Your Email" })}
label="Email Address"
margin="normal"
required
fullWidth
id="email"
name="email"
autoComplete="email"
autoFocus
value={"dchkang83@naver.com"}
/>
<TextField
{...register("password", { required: "Please Enter Your Password" })}
label="Password"
margin="normal"
required
fullWidth
name="password"
type="password"
id="password"
autoComplete="current-password"
value={"test1234"}
/>
<FormControlLabel
label="Remember me"
control={<Checkbox value="remember" color="primary" />}
/>
<Button
type="submit"
fullWidth
variant="contained"
sx={{ mt: 3, mb: 2 }}
>Sign in</Button>
<Grid container>
<Grid item xs>
<Link href="#" variant="body2">
Forgot password?
</Link>
</Grid>
<Grid item>
<Link href="#" variant="body2">
{"Sign Up"}
</Link>
</Grid>
</Grid>
</Box>
</Box>
<Copyright sx={{ mt: 8, mb: 4 }} />
</>
);
}
export default Login;
3. 화면 확인