반응형
발생 상황
개인 프로젝트 작업을 하던 중 Redux-toolkit 을 사용하여 axios.then 내부에서 dispatch 함수에 상태를 업데이트하는 레듀서 함수를 호출할 때 발생하였다.
발생 원인
리덕스의 레듀서는 내부적으로 불변성을 유지하기위해 immer 라이브러리를 사용한다. 다시 말해, 기존값을 수정하여 새로운 값을 반환(return)하는 변이성을 방지하는 역할을 수행한다. 즉, return 을 허용하지 않는다.
그러나 , 사용자의 실수로 추상화된 immer 라이브러리의 이러한 return 배제에 관한 규칙을 깨버리게 된다면(즉, 기존값을 건드려서 새로운 값을 반환하는 경우), 이에 대한 경고로서 에러를 띄우는데 그것이 아래의 메시지 이다.
[React Error] Error: [Immer] An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft. [React 오류] 오류: [Immer] immer 프로듀서가 새로운 값을 반환하고 동시에 draft를 수정했습니다. 새로운 값을 반환하거나 draft를 수정하거나 둘 중 하나만 해야 합니다. |
결국 이 문제를 해결하려면, immer 라이브러리에서 권장하는 방식을 코드에 적용하면 될 일이다.
해결방법(조치법)
해결하는 방법은 간단하다. 아래 예시는 리덕스 툴킷의 공식 문서에서 가져온 것인데, SAFE 로 주석이 달린 방식을 따라하면 된다.
const todosSlice = createSlice({
name: 'todos',
initialState: [],
reducers: {
// ❌ ERROR: mutates state, but also returns new array size!
// 상태를 수정하고, 새로운 배열 사이즈를 반환한다.
brokenReducer: (state, action) => state.push(action.payload),
// ✅ SAFE: the `void` keyword prevents a return value
// 안전 : void 키워드는 값의 반환을 예방한다.
fixedReducer1: (state, action) => void state.push(action.payload),
// ✅ SAFE: curly braces make this a function body and no return
// 안전 : 중괄호는 반환 값 없는 본문을 함수에 제공한다.
fixedReducer2: (state, action) => {
state.push(action.payload)
},
},
})
immer 라이브러리 공식 문서에서도 위의 방식으로 void 처리한 예시를 확인할 수 있었는데, 그 중에서 현재 문제 해결 방안으로 가장 적합한 방식을 정리해보았다.
참고자료
https://immerjs.github.io/immer/return/#inline-shortcuts-using-void
https://redux-toolkit.js.org/usage/immer-reducers(에서 Writing Reducers with Immer )
반응형
'리액트' 카테고리의 다른 글
[react] 리액트에서 상태에 대한 정리(1) - 상태 (0) | 2023.11.06 |
---|---|
[react] window.scroll 를 이용한 무한 스크롤 구현 시 문제되는 코드를 개선한 내용을 저장한 포스트 (0) | 2023.10.31 |
[리액트 npm error] CRA 환경에서 nth-check 취약점 문제 (0) | 2023.09.11 |
[리액트] 개인 코드 정리(리덕스 툴킷 타입스크립트 설정) (0) | 2023.07.26 |
[React] 리액트에서 카카오 맵 불러오기 (with kakao map) (0) | 2023.07.21 |