React를 공부하면서 props에 대해 배운 적이 있다. Props를 사용해서 상위에서 하위 컴포넌트로 데이터를 전달하고자 할 때, 필요한 하위 컴포넌트까지 계속해서 전달해야 하는 상황(props drilling)이 발생한다. 이를 해결하기 위해 React에서는 전역적으로 데이터를 공유할 수 있는 Context API 기능이 있지만, Context API의 경우에는 불필요한 재렌더링이 발생하는 단점이 있어 최근 사용이 많이 줄었다.
Redux는 Context API에서 발생했던 불필요한 렌더링을 줄이며 state를 관리할 수 있도록 돕는 서드파티 라이브러리이다. Redux는 상태 관리의 복잡성을 줄여줘 대규모 애플리케이션에서 유용하다. Redux가 가지고 있는 주요 개념 3가지는 다음과 같다.
- store : 데이터가 담겨있는 저장소
- dispatch
store의 내장 함수 중 하나로, state를 다른 값으로 업데이트하고 재렌더링을 해주는 함수이다. 이 함수는 상태 변화에 대한 action을 파라미터로 전달한다.
- dispatch
- action
상태에 변화를 주기 위한 이벤트를 정의하는 객체로, type 속성을 가지고 있으며 필요한 정보는 payload라는 속성을 통해 전달된다. - reducer
state가 어떻게 업데이트 될 것인지를 지정하는 함수로, state와 action을 인자로 받고 다음 state를 반환한다.
출처 : Redux Fundamentals, Part 1: Redux Overview | Redux
Redux 시작하기
1. Redux 설치하기
Redux Toolkit을 설치한다.
// NPM
npm install @reduxjs/toolkit react-redux
// Yarn
yarn add @reduxjs/toolkit
2. Reducer 생성하기
상태를 관리할 JavaScript 파일을 생성(store.js)하고, createSlice 함수를 사용하여 리듀서를 생성한다. createSlice는 상태와 액션을 함께 관리할 수 있도록 한다.
- let 슬라이스 이름 = createSlice({
name : "state 이름",
initialState : state 설정,
reducers: { 실행하고자하는 함수; }
})
// store.js
import {createSlice} from "@reduxjs/toolkit";
// num 이라는 슬라이스 이름 생성
let numSlice = createSlice({
name: 'num', //해당 값의 이름 설정
initialState : 3, //값 설정
reducers : { // 실제 동작하는 함수의 집합
increaseNum(state, action){
// state = 저장되어 있는 데이터
// action.payload = 상태 변경에 필요한 추가 정보를 담고있다
return state + action.payload;
},
decreaseNum(state, action) {
return state - action.payload;
}
}
});
3. Action 추출하기 & Store 설정하기
createSlice로 생성한 리듀서를 사용하여 Redux 스토어를 설정한다. Action의 경우 구조분해할당을 통해서 생성한 슬라이스에서 액션을 추출할 수 있다.
- export const { 함수명 } = 슬라이스 이름.actions;
- export default configureStore({
reducer : {
리듀서 이름 : 슬라이스 이름
}
})
// store.js
// 구조분해 할당을 통해 action 추출
export const { increaseNum, decreaseNum } = numSlice.actions;
// store에 저장, 'num'라는 키로 슬라이스를 스토어에 추가
export default configureStore({
reducer: {
num : numSlice.reducer
}
})
<< store.js 전체 코드 >>
// store.js
import {configureStore, createSlice} from "@reduxjs/toolkit";
// num 이라는 슬라이스 이름 생성
let numSlice = createSlice({
name: 'num', //해당 값의 이름 설정
initialState : 3, //값 설정
reducers : { // 실제 동작하는 함수의 집합
increaseNum(state, action){
// state = 저장되어 있는 데이터
// action.payload = 상태 변경에 필요한 추가 정보를 담고있다
return state + action.payload;
},
decreaseNum(state, action) {
return state - action.payload;
}
}
});
// 구조분해 할당을 통해 action 추출
export const { increaseNum, decreaseNum } = numSlice.actions;
// store에 저장
export default configureStore({
reducer: {
num : numSlice.reducer
}
})
4. <Provider> 컴포넌트로 Redux를 사용할 컴포넌트를 감싸기
Redux 스토어를 React 애플리케이션에 제공하기 위해 Provider로 감싸고, 사용할 store를 전달한다.
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import App from './App.jsx'
import './index.css'
import { Provider } from 'react-redux'
import store from './store.js'
createRoot(document.getElementById('root')).render(
<StrictMode>
<Provider store={store}>
<App />
</Provider>
</StrictMode>,
)
5. Redux 사용하기
useSelector를 통해서 스토어의 상태를 선택하여 컴포넌트에서 사용할 수 있고, useDispatch를 통해서 action을 받아올 수 있다.
- const 변수명 = useSelector(state => state.리듀서이름);
- const 변수명 = useDispatch();
import { useSelector, useDispatch } from 'react-redux';
import { increaseNum, decreaseNum } from '../store';
const Inner = () => {
const numValue = useSelector(state => state.num); // 상태 선택
const dispatch = useDispatch(); // 액션 디스패치 준비
// initial 값에 1을 더함
const handleIncrease = () => {
dispatch(increaseNum(1));
};
const handleDecrese = () => {
dispatch(decreaseNum(1))
}
return (
<div>
현재 값: {numValue}
<button onClick={handleIncrease}>증가</button>
<button onClick={handleDecrese}>감소</button>
</div>
);
};
export default Inner;
State를 가지고 있는 해당하는 컴포넌트(Inner.jsx)만 렌더링되고 나머지는 렌더링 되지 않는 모습을 볼 수 있다.
'Frontend > React' 카테고리의 다른 글
React : forwardRef에 대해서 (0) | 2024.09.15 |
---|---|
React : custom hook(커스텀 훅)을 사용해보자 (0) | 2024.09.10 |
React : Context API에 대해서 알아보자 (0) | 2024.09.06 |
React: Memo & useMemo & useCallback을 통한 성능개선 (0) | 2024.09.06 |
React : Lazy import을 통한 성능 개선 (0) | 2024.09.05 |
React: useReducer에 대해서 (0) | 2024.09.05 |
React: React에서 Styled Component 사용하기 (0) | 2024.09.04 |
React: useEffect에 대해서 (1) | 2024.09.03 |