Frontend/Error

[Redux-Toolkit] [Immer] An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft.

khakhalog 2023. 9. 15. 17:37

해당에러는 createSlice내의 reducer action함수를 작성하며 발생한 에러이다.

 

수정 전의 코드는 다음과 같다.

updateProcess: (
      state,
      {
        payload,
      }: PayloadAction<{
        currentProcessName: string;
        target: application;
        nextProcessName: string;
      }>,
    ) => {
      const { currentProcessName, target, nextProcessName } = payload;

      if (currentProcessName !== nextProcessName) {
        const currentProcessData = state.find(
          data => data.process === currentProcessName,
        ) as IkabanData;
        const nextProcessData = state.find(data => data.process === nextProcessName) as IkabanData;

        const targetIndex = currentProcessData.applications.findIndex(
          item => item.id === target.id,
        );

        if (targetIndex !== -1) {
          const updatedCurrentProcessApplications = currentProcessData.applications.filter(
            app => app.id !== target.id,
          );

          const updatedTarget = {
            ...target,
            schedule: '마감일을 입력하세요',
            processDescription: nextProcessName,
          };
          nextProcessData.applications.push(updatedTarget); // state를 직접 변경

          const newState = state.map(processData => {
            if (processData.process === currentProcessName) {
              return { ...processData, applications: updatedCurrentProcessApplications };
            } else if (processData.process === nextProcessName) {
              return { ...processData, applications: nextProcessData.applications };
            } else {
              return processData;
            }
          });
          return newState; // 새로운 state를 return
        }
      }
      return state;
    },

주석으로 표시한 부분인데 draft state를 직접 변경 and new state를 리턴 두 가지 작업이 충돌되어 발생한 에러였다.

해결방법으로는 간단한데, 둘 중에 하나의 방법으로만 state를 변경해주면된다.

  1. New state return :  원하는 변경 사항이 포함된 새 상태 객체를 생성하고 반환.
  2. Modify the Draft State : 초안 상태를 직접 수정. (ex. push, 등)

newState는 반드시 만들어져야한다고 생각하여 state를 직접 수정하는 코드를 없애고, 새 state를 반환하는 것으로 코드를 수정하였다.

updateProcess: (
      state,
      {
        payload,
      }: PayloadAction<{
        currentProcessName: string;
        target: application;
        nextProcessName: string;
      }>,
    ): IkabanData[] => {
      const { currentProcessName, target, nextProcessName } = payload;

      if (currentProcessName !== nextProcessName) {
        const currentProcessData = state.find(
          data => data.processType === currentProcessName,
        ) as IkabanData;
        const nextProcessData = state.find(
          data => data.processType === nextProcessName,
        ) as IkabanData;

        const targetIndex = currentProcessData.applications.findIndex(
          item => item.id === target.id,
        );

        if (targetIndex !== -1) {
          const updatedCurrentProcessApplications = currentProcessData.applications.filter(
            app => app.id !== target.id,
          );

          const updatedTarget = {
            ...target,
            schedule: '마감일을 입력하세요',
            processDescription: nextProcessName,
          };

          const newState: IkabanData[] = state.map(processData => {
            if (processData.processType === currentProcessName) {
              return { ...processData, applications: updatedCurrentProcessApplications };
            } else if (processData.processType === nextProcessName) {
              return {
                ...processData,
                applications: [...nextProcessData.applications, updatedTarget],
              };
            } else {
              return processData;
            }
          });
          return newState;
        }
      }
      return state;
    },