[MBTI 테스트] - 왜 함수형 업데이트를 하면 기존의 데이터가 사라지게 될까?
문제 상황
처음에는 authStore의 userInfo가 잘 저장되어 있다.
그. 런. 데 테스트를 완료하고 결과 확인하기 버튼을 누르면 userInfo가 사라지는 것을 볼 수 있다.
사용자가 테스트를 완료하고 결과 확인하기 버튼을 누를 때 다음과 같은 로직이 작동된다.
💻 기존의 결과 확인하기 버튼 로직
const handleSubmit = async (e) => {
e.preventDefault();
const { id, nickname } = userInfo;
const mbtiResult = calculateMBTI(answers);
addTestResult.mutate({
nickname,
mbtiResult,
userId: id,
date: new Date().toLocaleString(KOREAN),
visibility: false,
});
setUserInfo((prev) => ({ ...prev, mbtiResult }));
navigate(`/my-test-result?mbti=${mbtiResult}`);
};
로직을 잘못 작성한 것 같지는 않아 보이는데..
도대체 뭐가 문제인 것일까?!!?
(로직을 잘못 작성한 게 맞았다)
문제 원인 및 해결 과정
setUserInfo((prev) => ({ ...prev, mbtiResult }));
userInfo가 사라지는 이유는 여기 코드로 인해 발생하는 것이었다.
함수형 업데이트로 잘 작성했는데 왜 userInfo가 사라지는 것일까 곰곰이 생각하였다.
setUserInfo는 useState로 생성한 함수가 아니라 useAuthStore(zustand)에서 가져온 함수였다.
✅ useState로 생성한 함수가 아니기 때문에 함수형 업데이트를 사용할 수가 없었다.
이 사실을 깨닫자마자 스스로가 너무 바보처럼 느껴졌다.
그렇다면 setUserInfo 안에 원하는 객체 값만 전달해 주면 되는 것일까?
💻 기존의 useAuthStore 코드
import { create } from "zustand";
import { persist } from "zustand/middleware";
import { immer } from "zustand/middleware/immer";
const useAuthStore = create(
persist(
immer((set) => {
return {
accessToken: null,
setAccessToken: (value) => set({ accessToken: value }),
isLogin: !!localStorage.getItem("accessToken"),
setIsLogin: (value) => set({ isLogin: value }),
userInfo: null,
setUserInfo: (value) => {
set({ userInfo: value });
},
};
}),
{
name: "authStore",
}
)
);
export default useAuthStore;
useAuthStore에서 작성한 코드를 한 번 확인해 보자.
setUserInfo: (value) => {
set({ userInfo: value });
}
현재 setUserInfo의 로직에 수정이 필요한 것을 확인할 수 있다.
🚨 지금 로직은 기존의 값을 덮어쓰는 형식으로 작성되어 있다.
✅ 기존의 값에 새로운 값을 추가하는 형식으로 바꿔줘야 원하는 의도한 대로 코드가 돌아갈 수 있다!
💻 수정된 useAuthStore 코드
import { create } from "zustand";
import { persist } from "zustand/middleware";
import { immer } from "zustand/middleware/immer";
const useAuthStore = create(
persist(
immer((set) => {
return {
accessToken: null,
setAccessToken: (value) => set({ accessToken: value }),
isLogin: !!localStorage.getItem("accessToken"),
setIsLogin: (value) => set({ isLogin: value }),
userInfo: null,
setUserInfo: (value) => {
set((state) => {
state.userInfo = { ...state.userInfo, ...value };
});
},
};
}),
{
name: "authStore",
}
)
);
export default useAuthStore;
setUserInfo: (value) => {
set((state) => {
state.userInfo = { ...state.userInfo, ...value };
});
},
set 함수에서 이전 값을 가져와 새로운 값을 추가해 주는 로직으로 수정해 주었다!
💻 수정된 결과 확인하기 버튼 로직
const handleSubmit = async (e) => {
e.preventDefault();
const { id, nickname } = userInfo;
const mbtiResult = calculateMBTI(answers);
addTestResult.mutate({
nickname,
mbtiResult,
userId: id,
date: new Date().toLocaleString(KOREAN),
visibility: false,
});
setUserInfo({ mbtiResult });
navigate(`/my-test-result?mbti=${mbtiResult}`);
};
setUserInfo({ mbtiResult });
이제 setUserInfo에는 새로운 값만 넘겨주면 된다!
결과
이제 userInfo가 지워지지 않는다.
mbtiResult가 잘 추가되는 것을 확인할 수 있다~!