2차 공부/TIL

24.09.11 내 state는 꼭 state여야 할까? 개인과제 리팩토링

공대탈출 2024. 9. 11. 15:51

감사하게도 다른 내배캠 수강생분들께 여러 피드백을 받았었다.

추가기능이나 UX관련 피드백이 대부분이어서 해당 부분을 해결하고 있었다.

post요청이 끝날때까지 로딩을 보여주고 사용자가 결과페이지로 이동할 수 있게 해달라는 것 이었다.

공식문서 - useMutation.v4

tanstack query 공식문서의 usMutation부분에서 isLoading을 반환해주는 것을 확인하고 해당 post요청의 반환에서 isLoading을 받아 사용해보았다.

const { isLoading, mutate } = usePostMyTestMutation(targetQuestions.testTitle);

당연히 되겠지 하고 실행해보았지만, isLoading은 실행 유무와 상관없이 false도 true도 아닌 undefined값이 출력되었다.

isLoading = undefined

도저히 이해가 안갔다. 공식문서에서 분명 반환값으로 알려주고 있기 때문에 문제가 뭔지 커스텀훅으로 빼놓아서 그런 것인가 하며 여러 시도를 하다가, 튜터님께 찾아가서 여쭤보았다.

 

문제는 공식문서의 버전이었다.

해당 과제에서 사용한 tanstackquery의 버전은 v5+ 였는데, 내가 확인한 공식문서는 v4였다.

v5공식문서의 useMutation에선 isLoading을 반환하지않고, isPending을 반환해준다.

const { isPending, mutate } = usePostMyTestMutation(targetQuestions.testTitle);

따라서 isPending값을 반환받아주고, 해당 값을 사용하면 된다.


문제가 해결되고 어쩌다보니 코드 피드백을 잠깐 받았다.

const useAuthStore = create(
    persist(
        (set) => ({
            userInfo: {
                avatar: "",
                nickname: null,
                userId: null,
            },
            isLogin: false,
            login: (userObj) =>
                set(() => ({
                    userInfo: {
                        avatar: userObj.avatar ? userObj.avatar : "",
                        nickname: userObj.nickname,
                        userId: userObj.userId,
                    },
                    isLogin: true,
                })),
            logout: () =>
                set(() => ({
                	//...

유저정보를 관리하는 zustand관련 피드백이었는데, 여기서 사용되는 isLogin이 불필요하다는 것이었다.

isLogin은 결국 로그인, 로그아웃에 따라 bool값이 직접 변경되는 것인데, 이는 계산만으로 해결이 가능한 값이어서 state로 관리하면 올바르지 않은 사용이라고 하셨다.

react공식문서 - react로 사고하기

3번의 다른 state로 계산이 가능한 케이스이기 때문이다.

 

export const useIsLogin = () => useAuthStore((state) => state.isLogin);
export const useUserInfo = () => useAuthStore((state) => state.userInfo);
export const useLogin = () => useAuthStore((state) => state.login);
export const useLogout = () => useAuthStore((state) => state.logout);
export const useUpdateUserInfo = () => useAuthStore((state) => state.updateUserInfo);

zustand하단 코드에서 상태값이나 변경하는 로직을 각각 커스텀훅으로 분리하여 사용했었는데, 이곳에서 커스텀훅사용중 계산하여 return해주면 되는 것이었다.

 

export const useUserInfo = () => {
    const userInfo = useAuthStore((state) => state.userInfo)
    return {...userInfo, isLogin: ~~} 
};

결국 isLogin은 userInfo의 값에따라 결정되므로, 이렇게 useUserInfo에서 계산을 통해 같이 return해주거나

 

export const useIsLoggedin = () => {
    const currentUserInfo = useAuthStore((state) => state.userInfo);
    return !!currentUserInfo.userId;
};

이렇게 계산 후 isLoggedin값만 보내주어도 된다.

나는 후자를 선택했으며, 코드는 아래와 같이 변경하였다.

 

 const isLogin = useIsLoggedin();

    return (
        {isLogin ? (
            <>
                <button
                    className="px-2 text-center content-center rounded-2xl hover:bg-slate-400"
                    onClick={handleLogout}
                >
                    로그아웃
                </button>
                <Link
                    className="px-2 text-center content-center rounded-2xl hover:bg-slate-400"
                    to="/profile"
                >
                    마이페이지
                </Link>
            </>
        ) : (
            <>
                <Link
                    className="px-2 text-center content-center rounded-2xl hover:bg-slate-400"
                    to="/login"
                >
                    로그인
                </Link>
                <Link
                    className="px-2 text-center content-center rounded-2xl hover:bg-slate-400"
                    to="/signup"
                >
                    회원가입
                </Link>
            </>
        )}

 

앞으로 전역상태관리를 할 때에도 state로 관리를 해야하는 것인지, 단순 계산으로 관리가 가능한 값인지 한번 더 생각을 해야할 것 같다.

const isPasswordsEqual = userPassword === userPasswordCheck;

분명 회원가입페이지에서 비밀번호 확인 flag는 단순 계산에 의한 변수로 관리했으면서 왜 isLogin은 state로 관리하려 했을까