1. 헤더 분기하고 리덕스 설치하기
👉 클라이언트의 입장에서 로그인 하기는 사실 별 게 없어요.
우리 서버에 로그인 요청을 보내고, 응답을 받아서 토큰을 저장하면 끝입니다.
- 로그인 하고 나면 뭐가 바뀔까??
: 로그인을 하면 가장 먼저 생각 나는 건 헤더 컴포넌트 바뀌는 겁니다.
(헤더 컴포넌트 분기하기)
import React from "react";
import {Grid, Text, Button} from "../elements";
const Header = (props) => {
const [is_login, setIsLogin] = React.useState(false);
if(is_login){
return (
<React.Fragment>
<Grid is_flex padding="4px 16px">
<Grid>
<Text margin="0px" size="24px" bold>
헬로
</Text>
</Grid>
<Grid is_flex>
<Button text="내정보"></Button>
<Button text="알림"></Button>
<Button text="로그아웃"></Button>
</Grid>
</Grid>
</React.Fragment>
);
}
return (
<React.Fragment>
<Grid is_flex padding="4px 16px">
<Grid>
<Text margin="0px" size="24px" bold>헬로</Text>
</Grid>
<Grid is_flex>
<Button text="로그인"></Button>
<Button text="회원가입"></Button>
</Grid>
</Grid>
</React.Fragment>
)
}
Header.defaultProps = {}
export default Header;
- 리덕스 설치하기
👉 지금 우리는 로그인 상태를 알기 위해 매번 뭘하고 있나요? 그렇죠. 매번 쿠키를 체크하고 있습니다.
이걸 공용함수로 빼놨으니 비교적 편하게 하고는 있는데, 그래도 아직 좀 불편하죠.
로그인 상태를 리덕스에 저장하고 어떤 컴포넌트에서든 편히 볼 수 있게 해봐요. 🙂
# 이건 리덕스와 리덕스 모듈 내에서 경로 이동까지 하게 해줄 히스토리, 라우터와 히스토리를 엮어줄 모듈까지 한번에 설치해보는 거예요.
yarn add redux react-redux redux-thunk redux-logger history@4.10.1 connected-react-router@6.8.0
# 프론트엔드의 꽃 리액트 강의에서는 리듀서에서 뭔가를 바꿀 때 불변성 관리를 우리가 신경썼죠.
# 이번엔 우리가 신경쓰지 말고, 임머라는 패키지 사용해서 해볼거예요.
# 그리고 액션도 매번 맨 위에서 user/CREATE처럼 리듀서 모듈 명에 어떤 타입 넣어서 만들고,
# 그 아래에는 액션 생성 함수 만들어서 export 다 해주고 좀 귀찮았죠.
# 이걸 redux-actions라는 패키지로 좀 더 편하게 쓸거예요.
yarn add immer redux-actions
2. 유저 모듈 만들기
👉 설치한 redux-actions와 immer를 사용해서 액션과 액션 생성 함수, 리듀서를 만드는 방법, 알아봅시다!
이 immer는 불변성 관리를 , redux-actions는 좀 더 편한 액션 관리를 위해 사용해요.
→ Q. 왜 불변성 관리하는데 패키지까지 써야하나요?
A. 객체는 const로 선언해도 내용이 수정될 수 있죠! 그래서 스프레드 문법 ({...어떤 것} 이렇게 쓰는 거!) 등을 이용해서 수정되지 않게 주의해서 코드를 작성합니다. 그런데, 객체 구조가 복잡해지면 코드를 짜기가 번거로워요. 그래서 불변성을 신경 쓰지 않는 것처럼 써도 알아서 불변성을 유지해주는 immer를 사용하는거예요.
[시작하기 전에 잠깐!]
항상 폴더부터 만들고 시작해야해요!
src 폴더 아래에 redux폴더, 그리고 그 아래에 modules 폴더를 만들어주세요.
1) import 하기
// user.js
port { createAction, handleActions } from "redux-actions";
import { produce } from "immer";
import { setCookie, getCookie, deleteCookie } from "../../shared/Coo
2) 액션 타입 만들기
// user.js
const LOG_IN = "LOG_IN";
const LOG_OUT = "LOG_OUT";
const GET_USER = "GET_USER";
3) 액션 생성 함수 만들기
// user.js
const logIn = createAction(LOG_IN, (user) => ({ user }));
const logOut = createAction(LOG_OUT, (user) => ({ user }));
const getUser = createAction(GET_USER, (user) => ({ user }));
4) initalState 만들기
// user.js
const initialState = {
user: null,
is_login: false,
};
5) 리듀서 만들기 (feat.immer)
// user.js
export default handleActions(
{
[LOG_IN]: (state, action) =>
produce(state, (draft) => {
setCookie("is_login", "success");
draft.user = action.payload.user;
draft.is_login = true;
}),
[LOG_OUT]: (state, action) =>
produce(state, (draft) => {
deleteCookie("is_login");
draft.user = null;
draft.is_login = false;
}),
[GET_USER]: (state, action) => produce(state, (draft) => {}),
},
initialState
);
6) actionCreators 내보내기
// user.js
const actionCreators = {
logIn,
getUser,
logOut,
};
export { actionCreators };
3. 리덕스 스토어 만들기
👉 스토어 만들 때는 어떻게 하나요?
- combineReducers()를 사용해서 export한 reducer를 모아 root reducer를 만들고,
- 미들웨어를 적용해주고,
- createStore()를 사용해서 root reducer와 미들웨어를 엮어 스토어를 만든다!
// configureStore.js
// ** import 하기 **
import { createStore, combineReducers, applyMiddleware, compose } from "redux";
import thunk from "redux-thunk";
import { createBrowserHistory } from "history";
import { connectRouter } from "connected-react-router";
import User from "./modules/user";
// ** 스토어에 히스토리 넣어주기 **
export const history = createBrowserHistory();
// ** rootreducer 만들기 **
const rootReducer = combineReducers({
user: User,
router : connectRouter(history), // 라우터랑 history 연결
});
// ** rootreducer 만들기 **
const middlewares = [thunk.withExtraArgument({history:history})];
// 지금이 어느 환경인 지 알려줘요. (개발환경, 프로덕션(배포)환경 ...)
const env = process.env.NODE_ENV;
// ** 미들웨어 준비 **
// 개발환경에서는 로거라는 걸 하나만 더 써볼게요.
if (env === "development") {
const { logger } = require("redux-logger");
middlewares.push(logger);
}
// ** reduxdevTools 설정 **
const composeEnhancers =
typeof window === "object" && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({
// Specify extension’s options like name, actionsBlacklist, actionsCreators, serialize...
})
: compose;
// ** 미들웨어 묶기 **
const enhancer = composeEnhancers(applyMiddleware(...middlewares));
// ** 스토어 만들기 **
let store = (initialStore) => createStore(rootReducer, enhancer);
export default store();
4. 스토어에 주입하기
1) 리덕스와 컴포넌트 연결하기
👉 스토어를 주입할 때 Provider라는 걸 써요. Provider를 index.js에서 주입 할 거예요. 그 다음에는 App.js에서 원래 BrowserRouter와 Route를 써서 컴포넌트에 주입하던 history를 ConnectedRouter를 써서 리덕스랑 같은 history를 사용하도록 해줄게요. (그래야 히스토리를 공유하겠죠!)
- index.js에서 스토어 주입하기
import store from "./redux/configureStore";
import { Provider } from "react-redux";
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root")
);
- App.js
import { ConnectedRouter } from "connected-react-router";
import { history } from "../redux/configureStore";
...
function App() {
return (
<React.Fragment>
<Grid>
<Header></Header>
<ConnectedRouter history={history}>
<Route path="/" exact component={PostList} />
<Route path="/login" exact component={Login} />
<Route path="/signup" exact component={Signup}/>
</ConnectedRouter>
</Grid>
</React.Fragment>
);
}
2) 로그인 액션 실행하기 (리덕스 훅을 사용해서 간단하게 해봅니다)
- 로그인 페이지에서 리덕스 훅 사용하기
import React from "react";
import { getCookie, setCookie, deleteCookie } from "../shared/Cookie";
import { Text, Input, Grid, Button } from "../elements";
import { useDispatch } from "react-redux";
import {actionCreators as userActions} from '../redux/modules/user'
const Login = (props) => {
const dispatch = useDispatch();
let id = React.useRef();
let pw = React.useRef();
const login = () => {
dispatch(userActions.logInAction({user_name : "saebom"}));
};
return (
<React.Fragment>
<Grid padding="16px">
<Text size="32px" bold>
로그인
</Text>
<Grid padding="16px 0px">
<Input
label="아이디"
placeholder="아이디를 입력해주세요."
_onChange={() => {
console.log("아이디 입력했어!");
}}
refInfo={id}
/>
</Grid>
<Grid padding="16px 0px">
<Input
label="패스워드"
placeholder="패스워드 입력해주세요."
_onChange={() => {
console.log("패스워드 입력했어!");
}}
refInfo={pw}
/>
</Grid>
<Button
text="로그인하기"
_onClick={() => {
login();
}}
></Button>
</Grid>
</React.Fragment>
);
};
export default Login;
- 로그인 하면 메인 페이지로 이동하기
// middleware actions
const logInAction = (user)=>{
return function (dispatch, getState, {history}) {
console.log(history);
dispatch(logIn(user));
history.push("/");
}
}
...
// action creator export
const actionCreators = {
logIn,
getUser,
logOut,
loginAction,
};
3) 헤더에서 스토어 데이터 보기 (리덕스 훅을 사용해서 간단하게 해봅니다)
- Header.js에서 리덕스 훅 사용하기
import { useSelector, useDispatch } from "react-redux";
import { actionCreators as userActions } from "../redux/modules/user";
...
const Header = (props) => {
const dispatch = useDispatch();
const is_login = useSelector((state) => state.user.is_login);
if(is_login){
return (
<React.Fragment>
<Grid is_flex padding="4px 16px">
<Grid>
<Text margin="0px" size="24px" bold>
헬로
</Text>
</Grid>
<Grid is_flex>
<Button text="내정보"></Button>
<Button text="알림"></Button>
<Button text="로그아웃" _onClick={() => {dispatch(userActions.logOut({}));}}></Button>
</Grid>
</Grid>
</React.Fragment>
);
}
return (
<React.Fragment>
<Grid is_flex padding="4px 16px">
<Grid>
<Text margin="0px" size="24px" bold>헬로</Text>
</Grid>
<Grid is_flex>
<Button text="로그인"></Button>
<Button text="회원가입"></Button>
</Grid>
</Grid>
</React.Fragment>
)
}
Header.defaultProps = {}
export default Header;
'항해 중 > 5주차 리액트 심화반' 카테고리의 다른 글
3주차 - Debounce, Throttle (0) | 2021.12.01 |
---|---|
2주차 - 로그인 유지하기 / 로그아웃 구현하기 / 퀴즈 (0) | 2021.11.30 |
2주차 - 웹 저장소(feat. 토큰) (0) | 2021.11.30 |
2주차 - 토큰 기반 인증(OAuth 2.0, JWT) (0) | 2021.11.30 |
2주차 - Promise (0) | 2021.11.30 |
댓글