useReducer
React에서 제공하는 훅 중 useReducer라는 상태 관리 훅이 있다.
useState와 마찬가지로 상태를 관리하지만,
컴포넌트로부터 로직을 분리하기 때문에 관리해야하는 상태나 로직이 복잡한 상황에서 useState보다 컴포넌트를 좀 더 깔끔히 관리할 수 있다는 장점이 있다.
import { useReducer } from 'react';
function reducer(state, action) {
// ...
}
function MyComponent() {
const [state, dispatch] = useReducer(reducer, { age: 42 });
// ...
}
Parameter, Return
const [state, dispatch] = useReducer(reducer, initialArg, init?)
위와 같이 useReducer에는 3개의 파라미터를 넘겨줄 수 있다.
- reducer
- required
- 상태를 업데이트하는 함수
- <pre>(state, action) => {...} </pre>
- initialArg
- required
- 초기 상태값
- init
- optional
- 초기 상태를 정의하는 함수 : 2번째 인자인 initalArg를 파라미터로 받는 함수이다.
- <pre>(initialArg) => {...}</pre>
Reducer
Reducer는 상태를 업데이트하는 함수로,
dispatch를 호출하면 dispatch의 인자가 reducer의 action으로 넘어가며 호출된다.
아래와 같이 생각하면 편하다.
function dispatch(action) {
reducer(this.state, action)
}
파라미터
Reducer는 2개의 파라미터를 가진다.
- state : 현재 상태
- action: 사용자에 의해 수행되는 액션으로, dispath 함수를 호출할 때 넘기는 인자이다.
- <pre>dispath({type: 'age', age: 10})</pre> 를 통해 dispatch 함수를 호출하는 경우
<pre>{type: 'age', age: 10}</pre>이 action이다. - 어떤 형식의 타입이든 올 수 있지만, 컨벤션은 type을 같이 넘겨서 어떤 종류의 행위인지 명시해주는 것이다.
- <pre>dispath({type: 'age', age: 10})</pre> 를 통해 dispatch 함수를 호출하는 경우
Return
Reducer는 바꾸고자하는 상태를 return 해야 한다.
Reducer를 생성할 때는 아래 두가지 사항을 주의해야한다.
- 첫번째 인자인 state는 readonly이므로 수정하지 말고 새로운 object를 return 할 것
- 여러 key를 가지는 object인 경우 변경하는 대상 외의 값들을 누락하지 않도록 주의할 것
- reducer는 pure 함수여야 한다.
주의사항 1
첫번째 인자인 state는 readonly 이기 때문에 수정하기보다는 새로운 object를 만들어서 return 해야 한다.
🙅♂️ 안좋은 방법
function reducer(state, action) {
switch (action.type) {
case 'incremented_age': {
// 🚩 Don't mutate an object in state like this:
state.age = state.age + 1;
return state;
}
}
}
🙆♂️ 좋은 방법
function reducer(state, action) {
switch (action.type) {
case 'incremented_age': {
// ✅ Instead, return a new object
return {
...state,
age: state.age + 1
};
}
}
}
주의사항2
여러 key를 가지는 object인 경우 다른 값들에 대해 영향을 미칠 수 있음을 고려해야 한다.
<pre>{a: ~~, b: ~~, c: ~~}</pre> 형태의 obejct가 있는 경우,
reducer 내에서 <pre>return {a: 10}</pre> 을 하게 된다면 상태는 b와 c가 없는 a만 존재하는 object로 변화하게 된다.
때문에 <pre>return {...state, a: 10}</pre> 과 같이 spread 연산자를 써서 다른 값들에 대해서도 유지해야한다.
초기값이<pre>{age: 10, name: '홍길동'}</pre> 라는 상태가 있을 때 age를 20으로 바꿔보자.
그를 위해 <pre>dispatch({type: 'age', age: 20})</pre>를 호출한다.
그러면 reducer의 두번째 인자로 object가 넘어온다.
그걸 받아서 바꾸고자하는 새로운 상태값을 return 해주면 된다.
아래 4번 줄 처럼 return 시에는 기존 state의 다른 값(name)이 누락되지 않도록 고려해야한다.
function reducer(state, action) {
switch (action.type) {
case 'age':
return { ...state, age: action.age };
default:
return state;
}
}
주의사항3
Reducer는 pure 해야하며, 비동기 함수는 원칙적으로는 받지 않는다.
상태관리 시 비동기 로직이 필요한 경우가 있다. 이를 위해 서칭 중 괜찮은 글을 찾았다.
필요 시 아래 글처럼 커스텀 훅을 만들거나 아래 글에서 제시해주는 패턴에 따라 코드를 작성하면 될 듯하다.
https://velog.io/@allenk/useReducer로-비동기-로직-다루기
참고
- React Reference
https://react.dev/reference/react/useReducer - useReducer의 장점
https://eun-jee.com/post/front-end/react/04-useReducer/#언제-사용할까 - useReducer와 비동기 함수
https://velog.io/@allenk/useReducer로-비동기-로직-다루기
'Coding > [Web] Frontend' 카테고리의 다른 글
[React] useImperativeHandle (forwardRef의 ref 커스터마이징) (1) | 2024.01.04 |
---|---|
[React] Store 유지한 채 페이지 새로고침하기 (Remounting) (0) | 2023.12.24 |
[CSS] 스타일 우선순위 (0) | 2023.03.27 |
[JavaScript] 브라우저 로드 트리거 : DOMContentLoaded vs load (0) | 2023.03.27 |
[CSS] 선택자 (0) | 2023.03.21 |
댓글