간단한 Redux with 실제 코드

레덕스를 모르시는 분은 레덕스의 개념을 보고 오시면 도움이 많이 됩니다.
typescript 기준으로 코드예제가 되어 있습니다.
npx create-react-app 커맨드를 통해 리액트가 프로젝트가 시작되신 분들이 보시면 됩니다.
npm install --save redux @types/redux
JavaScript
npm install --save react-redux @types/react-redux
JavaScript
npm install --save redux-thunk @types/redux-thunk //not required for synchronous project //middleware?
JavaScript
npm install --save redux-devtools-extension @types/redux-devtools-extension
JavaScript
1.
reducers 폴더 만들기
2.
store 파일 만들기
3.
store 파일을 가져오기
4.
useSelector, useDispatch 사용하기
1.
reducers 폴더 만들기
src/reducers
이안에, 두개의 파일을 만듭니다. (index.ts, user.ts) 계속 여기에 추가가 될 예정입니다.
typescript → ts
src/reducers/user.ts
export const SET_JWT_TOKEN = 'SET_JWT_TOKEN' as const; export const INCREASE = 'INCREASE' as const; export const setJwtToken = (jwtToken:string) => ({ type: SET_JWT_TOKEN, payload: jwtToken, }); type UserInitialType = { jwtToken: string | null, } const initialState = { jwtToken: null, cnt: 0, } type UserActionType = | ReturnType<typeof setJwtToken> const user = (state:UserInitialType = initialState, action:UserActionType) => { switch (action.type) { case SET_JWT_TOKEN:{ return { ...state, jwtToken: action.payload, } } case INCREASE: { return { ...state, cnt: state.cnt + 1 } } default: return state; } }; export default user;
JavaScript
그리고 위의 user.ts를 아래 index.ts에서 임포트 한후, combineReducers에 집어 넣습니다.
src/reducers/index.ts
import {combineReducers} from 'redux'; import user from './user'; export const USER_LOGOUT = "USER_LOGOUT" export const userLogOut = () => ({ type: USER_LOGOUT, }); const appReducer = combineReducers({ user, //여기에 추가될 reducer를 선언하기. }) const rootReducer = (state:any, action:any) => { if (action.type === USER_LOGOUT) { state = undefined; } return appReducer(state, action); }; export default rootReducer
JavaScript
2. store 파일 만들기
src/config/store.js (없으면 만들어주세요)
import reducers from '../reducers'; import {applyMiddleware, createStore} from 'redux'; import ReduxThunk from 'redux-thunk'; import {composeWithDevTools} from 'redux-devtools-extension'; export default createStore( reducers, {}, composeWithDevTools(applyMiddleware(ReduxThunk)), );
JavaScript
리듀서를 가져오고, redux를 임포트 하고, redux-thunk도 임포트 합니다. 이 스토어에 우리의 모든 글로벌 스테이트가 저장이 되고 변경이 됩니다. 그리고 컴포넌트는 이 스토어에 접근해서 데이터를 읽는 것 입니다.
3. store파일을 가져오기
이 store파일을 우리의 가장 상위인 index.js로 가져 오고 설치 합시다.
설치 방법은 다음과 같습니다.
import React from 'react'; import ReactDOM from 'react-dom'; import './index.css'; import Routes from './Routes'; import reportWebVitals from './reportWebVitals'; import { Provider } from 'react-redux'; import store from './config/store'; ReactDOM.render( <Provider store={store}> <Routes/> </Provider>, document.getElementById('root') ); reportWebVitals();
JavaScript
<Routes/> 로 선언되었던 부분이 Provider 로 감싸졌습니다. Provider에 쌓여있는 부분은 redux에 store에 접근 가능합니다. 즉 appState에 접근이 가능하다는 거죠. 우리의 모든 컴포넌트가 그렇게 되도록 가장 상위단에 Provider를 선언해주면 됩니다.
4. useDispatch, useSelector 사용하기.
appState를 업데이트 하거나, appState를 불러오는 걸 해보려고 합니다.
먼저 불러오기
useSelector를 react-redux로 부터 불러 옵니다.
우리의 appState에 user 리듀서에 jwtToken을 불러 옵니다.
import React from 'react'; import {Link, useHistory} from 'react-router-dom'; import { useSelector } from 'react-redux' const Home = () => { const history = useHistory(); const jwtToken = useSelector((state:any) => state.user.jwtToken); return <div> <Link to="/daily">to daily!</Link> <div>{jwtToken}</div> <div onClick={(e:any) => { history.push("/daily"); }}>Another way to go daily</div> </div> } export default Home
JavaScript
아래처럼 불러 옵니다.
const jwtToken = useSelector((state:any) => state.user.jwtToken);
JavaScript
실제 {}로 프린트 하시면 됩니다.
업데이트 하기
업데이트를 하기 위해선 dispatch를 해서, 리듀서를 통하여 우리의 appState를 업데이트 해줘야 합니다.
import React from 'react'; import { useDispatch, useSelector } from 'react-redux' import {setJwtToken} from '../reducers/user'; const Home = () => { const history = useHistory(); const dispatch = useDispatch(); const jwtToken = useSelector((state:any) => state.user.jwtToken); const updateJwtToken = () => { const makeid = (length:number) => { var result = ''; var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; var charactersLength = characters.length; for ( var i = 0; i < length; i++ ) { result += characters.charAt(Math.floor(Math.random() * charactersLength)); } return result; } dispatch(setJwtToken(makeid(5))); } return <div> <div>{jwtToken}</div> <div onClick={(e:any) => { updateJwtToken(); }}>update jwtToken</div> </div> } export default Home
JavaScript
useDispatch를 임포트 합니다. 그 후 dispatch라는 이름으로 대입해서 사용하도록 합니다.
선언했던 reducer에 있는 setJwtToken도 임포트 합니다.
클릭을 할 때마다 jwtToken의 값을 바꿔주기 위해 makeid함수를 만들었습니다.
참고로, dispatch(setJwtToken(someRandom))이 실행 되면, reducers/memo.ts 로 갑니다.
export const setJwtToken = (jwtToken:string) => ({ type: SET_JWT_TOKEN, payload: jwtToken, }); /// switch (action.type) { case SET_JWT_TOKEN:{ return { ...state, jwtToken: action.payload, } } default: return state; }
JavaScript
{ type: SET_JWT_TOKEN, payload: jwtToken, }//해당 액션이 실행이 되면
JavaScript
jwtToken이 업데이트가 됩니다.
여러분들이 관리해야 할 state가 많아진다면, 적절히 폴더를 나누어서 구성을 해보실 수 있습니다.
이렇게 하면, 브라우저를 리프레시를 하게 되면 레덕스의 스테이트가 다시 초기화가 되는 것을 볼 수 있습니다.
따라서, 이제 마무리 작업을 해줘야 합니다.
npm install --save redux-persist
CSS
import { persistStore, persistReducer } from 'redux-persist'; import storage from 'redux-persist/lib/storage'; const persistConfig = { key: 'root', storage }; const enhancedReducer = persistReducer(persistConfig, reducers); export default function configureStore() { const store = createStore( enhancedReducer, {}, composeWithDevTools(), ); const persistor = persistStore(store); return {store, persistor}; }
JavaScript
index.js
import App from './App'; import React from 'react'; import ReactDOM from 'react-dom'; import './index.css'; // import Routes from './Routes'; import reportWebVitals from './reportWebVitals'; import { Provider } from 'react-redux'; import { PersistGate } from 'redux-persist/integration/react'; import configureStore from './config/store'; const {store, persistor} = configureStore(); ReactDOM.render( <Provider store={store}> <PersistGate laoding={null} persistor={persistor}> <App /> </PersistGate> </Provider>, document.getElementById('root') ); reportWebVitals();
JavaScript