React Redux 적용
npm install redux react-redux @reduxjs/toolkit
@reduxjs/toolkit
- Redux의 복잡성을 줄이기 위해 만들어진 도구
- action 생성, reducer, middleware 등 Redux와 관련된 기능들을 효율적으로 구현할 수 있다.
<Provider>
- 최상위 component에서 하위 component들에 store를 전달해 준다.
- store이라는 props에 import 한 store를 넣어준다.
import React from 'react';
import ReactDOM from 'react-dom/client';
import {Provider} from 'react-redux';
import store from './store';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>
);
useSelector()
- 하위 component에서 <Provider>로 전달받은 store의 state값을 조회하기 위한 hook 함수
- 인자로 콜백을 받고 해당 콜백은 state를 매개변수로 받을 수 있고, 원하는 state의 값만 추출해 반환할 수 있다.
useDispatch()
- action을 발생시키는 dispatch 함수를 실행하는 hook 함수
- 인자로 원하는 ㅊction 객체를 넘겨줘야 한다.
import {useSelector, useDispatch} from 'react-redux';
//useSelector()를 이용하여 state 객체의 number키의 값을 반환받는다.
const number = useSelector(state => state.number);
//useDispatch()를 이용하여 action객체를 넣고 해당 action을 발생시킬수 있는 함수를 반환받는다.
const dispatch = useDispatch();
//사용 예제
<button onClick={()=>{dispatch({ type: 'INCREASE' })}}>+1</button>
Redux Toolkit (@reduxjs/toolkit)
configureStore()
- createStore() 함수보다 더욱 편리한 방법으로 Redux store을 생성하는 함수
- 여러 middleware와 reducer를 쉽게 통합할 수 있다
createSlice()
- reducer와 action을 함께 생성하는 함수
- 슬라이스라는 개념을 사용하여 action type, action 생성 함수, reducer를 한 번에 정의한다.
store 생성 & reducer 및 action 정의하기
// createSlice, configureStore 함수 불러오기
import {createSlice, configureStore} from '@reduxjs/toolkit';
// createSlice 안에 들어가는 객체의 속성들은 name, initialState, reducer로 고정
// 이때 createSlice 함수로 반환된 객체는 reducer와 actions 속성이 포함되어있어 store 생성할때 .reducer로 접근하고
// action을 내보낼때 .actions로 접근하여 내보낼수 있다.
const initialCounterState = {counter: 0}
const counterSlice = createSlice({
name: 'counter',
initialState: initialCounterState,
reducers: {
//reducer속성안에 action 함수들을 미리 정의해준다.
//이때 action 함수들을 현재 상태를 가지고 있는 state와 action을 받을 수 있고, 추가적인 데이터는 무조건 action.payload로 받는다
increment(state) {
state.counter++;
},
decrement(state) {
state.counter--;
},
calculate(state, action) {
state.counter = state.counter + action.payload;
},
},
});
const initialAuthState = {isLogin: false}
const authSlice = createSlice({
name: 'auth',
initialState: initialAuthState,
reducers: {
login(state) {
state.isLogin = true;
},
logout(state) {
state.isLogin = false;
},
}.
});
//configureStore 안에 사용할 reducer들을 객체로 한번에 정의할 수 있다.
const store = configureStore({
reducer: { counter: counterSlice.reducer, auth: authSlice.reducer },
});
// action들을 내보낼때
export const counterActions = counterSlice.actions;
export const authActions = authSlice.actions;
export default store;
하위 component들에게 store 전달하기
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { Provider } from 'react-redux';
import store from './store';
// Provider component에 store props로 configureStore()함수로 생성된 store를 넣어준다
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>
);
하위 component에서 store 접근하기
//useSelector(), useDispatch() 불러오기
import { useSelector, useDispatch } from 'react-redux';
//action들 불러오기
import { counterAction, counterAction } from './store/counter';
//component 생성
export default function Counter() {
//useSelector를 이용하여 state에서 필요한 값만 추출하고 할당
const counter = useSelector((state) => state.count.counter);
const login = useSelector((state) => state.login.isLogin);
//만든 dispatch 함수의 인자로 import 한 action객체의 특정 action 함수를 넣어준다
const dispatch = useDispatch();
const add = () => {
dispatch(counterAction.increment());
};
const minus = () => {
dispatch(counterAction.decrement());
};
//counterAction.calc() 안에 들어가는 인자는 reducer안에 정의된 calc함수에서 action.payload로 접근가능
const calc = () => {
dispatch(counterAction.calc(5));
};
return (
<div>
<h2>{counter}</h2>
<button onClick={add}>ADD</button>
<button onClick={minus}>SUBTRACT</button>
<button onClick={calc}>CALC</button>
{login ? (
<>
<div>로그인 하셨습니다.</div>
<button onClick={() => dispatch(loginAction.logout())}>로그아웃</button>
</>
) : (
<>
<div>로그아웃 하셨습니다.</div>
<button onClick={() => dispatch(loginAction.login())}>로그인</button>
</>
)}
</div>
);
}
느낀 점
프로젝트 규모가 커질수록 더욱 복잡한 로직을 처리하고 방대한 데이터를 전역적으로 제공하려면 상태의 개수가 엄청 많아지는 문제가 발생하는데, @reduxjs/toolkit가 제공하는 함수들을 사용하여 특정 상태만 다루는 reducer와 action들을 각각 정의하고 사용함으로써 해당 문제를 해결할 수 있을 것 같습니다. (페이지의 테마 상태, 사용자 로그인 상태 등).
'POSCO x CODINGOn 웹개발자 양성 부트캠프' 카테고리의 다른 글
| [포스코x코딩온] 웹개발자 풀스택 과정 15주차 회고 | React: [TypeScript] (0) | 2023.10.22 |
|---|---|
| [포스코x코딩온] 웹개발자 풀스택 과정 15주차 회고 | TypeScript (0) | 2023.10.11 |
| [포스코x코딩온] 웹개발자 풀스택 과정 14주차 회고 | JavaScript: [Redux] (0) | 2023.10.05 |
| [포스코x코딩온] 웹개발자 풀스택 과정 14주차 회고 | React: [React Hook Form, React Context API] (2) | 2023.10.04 |
| [포스코x코딩온] 웹개발자 풀스택 과정 13주차 회고 | React: [React Router DOM] (0) | 2023.10.01 |