Zustand

Zustand로 React 상태 업데이트 지연 문제 해결하기

해보구 2025. 2. 10. 12:28

React에서 상태를 관리할 때 useState를 사용하면 비동기 업데이트로 인해 최신 값이 반영되지 않는 경우가 있다. 특히, 디바운싱을 적용한 비밀번호 입력에서 setState가 지연되면서 서버로 전송되는 값이 최신 값이 아니라 이전 값(3글자)만 전송되는 문제가 발생했다.

 

처음에는 setTimeout을 추가해서 상태가 업데이트될 시간을 주려고 했지만, 여전히 최신 값을 보장하지 못했다. 그래서 Zustand를 활용하여 전역 상태로 관리하면 해결될 것 같았다. 하지만 처음 시도한 방식으로는 상태가 여전히 클로저에 묶여 있고, 제출 시점에서 최신 상태를 반영하지 못하는 문제가 있었다.

 

 

비밀번호 입력 로직에서 useState를 사용하면 다음과 같은 문제가 발생한다.

  1. setPassword(val) 호출 시 상태가 업데이트되지만, 비동기 업데이트이므로 렌더링이 완료될 때까지 password 값이 변하지 않는다.
  2. 따라서 submitPayload()가 실행되는 시점에는 password가 여전히 이전 값(예: 3글자)로 남아 있어서 서버로 잘못된 값이 전달된다.

즉, 콘솔 디버깅을 해보면 다음과 같은 로그가 찍힌다.

 

비밀번호 자동저장:  3214
✅ 비밀번호 자동저장 후 제출: 3214
🚀 Debug: storeName: 123
🚀 Debug: storePlace: 234
🚀 Debug: password: 321  <-- 비동기 업데이트로 인해 여전히 3글자만 전송됨

 

useState 대신 Zustand를 사용하면 이 문제를 해결할 수 있을 것 같았다. 그래서 useFormStore를 만들어 상태를 글로벌하게 관리했지만, 상태 업데이트 자체는 여전히 useState처럼 동작했다. 결국, Zustand를 사용해도 useFormStore()에서 값을 가져올 때 여전히 이전 값이 남아 있는 경우가 발생했다.

 

 

해결 방법

// 최신 Zustand 상태를 직접 가져오기
  const { storeName, storePlace, password } = useFormStore.getState();

Zustand는 기본적으로 상태를 동기적으로 업데이트하지만, 컴포넌트 내부에서 구독한 상태(즉, 훅을 통해 받은 값)는 여전히 클로저에 묶여 최신 상태를 반영하지 못할 수 있다. 이를 해결하기 위해 useFormStore.getState()를 사용하여 최신 상태를 직접 가져오도록 변경했다.

 

 

Zustand 상태 관리 코드

import { create } from "zustand";

interface FormState {
  storeName: string;
  storePlace: string;
  password: string;
  setStoreName: (name: string) => void;
  setStorePlace: (place: string) => void;
  setPassword: (password: string) => void;
}

export const useFormStore = create<FormState>((set) => ({
  storeName: "",
  storePlace: "",
  password: "",
  setStoreName: (name) => set({ storeName: name }),
  setStorePlace: (place) => set({ storePlace: place }),
  setPassword: (password) => set({ password }),
}));

결과

  • useFormStore.getState()를 사용하여 항상 최신 상태를 반영하게 변경
  • 이제 제출 시점에서 4글자가 정확하게 서버에 전달됨
  • React의 비동기 업데이트로 인한 클로저 문제를 해결

 

회고

 

처음에는 Zustand를 사용하면 useState보다 더 쉽게 상태 관리를 할 수 있을 거라 생각했는데, 상태를 구독하는 방식에서는 비슷한 문제가 발생할 수 있다는 점을 알게 되었다. useState에서 상태를 직접 넘겨 해결하는 것처럼, Zustand에서도 getState()를 사용해 직접 가져오는 것이 더 확실한 해결 방법이었다.

 

비동기 상태 업데이트는 예상치 못한 곳에서 버그를 유발할 수 있다. 이번 문제를 통해 상태를 어떻게 관리해야 하는지 다시 고민하게 되었고, Zustand가 동기적이라고 해서 항상 최신 상태를 보장하는 것은 아니라는 점을 깨달았다. 다음에는 비슷한 문제가 발생하면 먼저 상태 업데이트의 타이밍을 체크하고, 직접 상태 값을 가져올 수 있는 방법이 있는지 확인해야겠다는 생각이 들었다.

 

'Zustand' 카테고리의 다른 글

Zustand로 글로벌 상태 관리 도입기  (0) 2025.02.05