본문 바로가기

리액트

[React Error] Error: [Immer] An immer producer returned a new value ... 을 해결하려면

반응형

발생 상황

개인 프로젝트 작업을 하던 중 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 )

https://stackoverflow.com/questions/60806105/error-an-immer-producer-returned-a-new-value-and-modified-its-draft-either-r

반응형