개요
Zustand, Recoil, RTK, Jotai와 같은 external store를 사용하고 있는데 state를 localstorage에 저장해야 하나요? 이번 프로젝트를 진행하면서 Zustand를 사용하게 됐는데 persist라는 옵션이 있었습니다. 많은 프로젝트에서 수요가 있었다는 뜻인것처럼 다른 라이브러리 또한 같은 옵션을 제공했습니다.
단순한 Zustand 예시
import { create } from 'zustand'
import { combine } from 'zustand/middleware'
const useBearStore = create(
combine({ bears: 0 }, (set) => ({
increase: (by: number) => set((state) => ({ bears: state.bears + by })),
})),
)
persist 적용 Zustand + Next.js 예시
import { create } from 'zustand'
import { persist } from 'zustand/middleware'
interface BearState {
bears: number
increase: (by: number) => void
}
const useBearStore = create<BearState>()(
persist(
(set) => ({
bears: 0,
increase: (by) => set((state) => ({ bears: state.bears + by })),
}),
{ name: 'bearStore' },
),
)
그냥 미들웨어 하나 붙히면 바로 localStorage에 저장되는거 같겠지만 Next.js Server Side Rendering을 사용한다면, Server와 Client간 렌더된 컴포넌트가 다르다는 에러를 던집니다.
- Text content does not match server-rendered HTML
- Hydration failed because the initial UI does not match what was rendered on the server
- There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering
이 문제를 해결하기 위해선 조금 귀찮은 방법을 사용해야하는데, 기존 useBearStorage를 사용하는 대신 아래와 같은 Store를
// useStore.ts
import { useState, useEffect } from 'react'
const useStore = <T, F>(
store: (callback: (state: T) => unknown) => unknown,
callback: (state: T) => F,
) => {
const result = store(callback) as F
const [data, setData] = useState<F>()
useEffect(() => {
setData(result)
}, [result])
return data
}
export default useStore
만들고 해당 컴포넌트에서 아래와 같이 호출해야 합니다.
// yourComponent.tsx
import useStore from './useStore'
import { useBearStore } from './stores/useBearStore'
const bears = useStore(useBearStore, (state) => state.bears)
데모
https://zustand-next-14-example.vercel.app/
https://github.com/2bro2/zustand-next-14-example
참고
https://docs.pmnd.rs/zustand/integrations/persisting-store-data
'software engineering > frontend' 카테고리의 다른 글
reduce, reduceRight 그리고 functional programming (0) | 2024.04.27 |
---|---|
Preact 그리고 Signals (1) | 2024.02.14 |
Next13 import-meta-env 도입기 그리고 주의점 (2) | 2024.02.12 |
JSX Conditional rendering && 와 삼항연산자 (0) | 2023.12.31 |
React TypeScript Cheatsheet (0) | 2023.12.19 |