오늘 한 일
- gloddy 개발
감기에 걸렸다..🥲
사실 2주 전부터 지금까지 계속 코감기가 있었는데 오늘은 정말 힘들었다.
카페에서 계속 기침하고 콧물이 나와서 집중이 안됐다. 그래서 공부를 많이 하진 못하고 일찍 잘 예정이다.
zustand를 Context로 사용해서 범위 제한하기
전 버전에서는 zustand/context
의 createContext
를 제공했지만, 4 버전으로 넘어오면서 이렇게 사용하도록 권장하고 있다. (5에서는 제거될 예정)
// store.tsx
+ import { createContext, useContext } from "react";
- import create from "zustand";
- import createContext from "zustand/context";
+ import { createStore, useStore } from "zustand";
- const useStore = create((set) => ({
+ const store = createStore((set) => ({
bears: 0,
increasePopulation: () => set((state) => ({ bears: state.bears + 1 })),
removeAllBears: () => set({ bears: 0 })
}));
+ const MyContext = createContext()
+ export const Provider = ({ children }) => <MyContext.Provider value={store}>{children}</MyContext.Provider>;
+ export const useMyStore = (selector) => useStore(useContext(MyContext), selector);
이렇게 사용하면 Provider
로 감싸진 컴포넌트에서만 useMyStore
를 사용할 수 있다.
createStore? create?
zustand의 내부 코드를 보면 이렇게 되어있다.
const createImpl = <T>(createState: StateCreator<T, [], []>) => {
if (import.meta.env?.MODE !== 'production' && typeof createState !== 'function') {
console.warn(
"[DEPRECATED] Passing a vanilla store will be unsupported in a future version. Instead use `import { useStore } from 'zustand'`."
)
}
const api = typeof createState === 'function' ? createStore(createState) : createState
const useBoundStore: any = (selector?: any, equalityFn?: any) =>
useStore(api, selector, equalityFn)
Object.assign(useBoundStore, api)
return useBoundStore
}
export const create = (<T>(createState: StateCreator<T, [], []> | undefined) =>
createState ? createImpl(createState) : createImpl) as Create
반환 타입을 보면 이렇다.
createStore<T>
:StoreApi<T>
create<T>
:UseBoundStore<StoreApi<T>>
결국 create
는 createStore
를 사용해서 만든 api를 useStore
에 넘겨주는 역할을 한다.
타입스크립트에서 사용하기 (createStore ver. / create ver.)
타입스크립트를 사용한다면 이런식으로 작성할 수 있을 것 같다.
// createStore ver.
import { createContext, useContext } from 'react'
import { createStore, useStore } from 'zustand'
type State = {
bears: number
increasePopulation: () => void
removeAllBears: () => void
}
const store = createStore<State>((set) => ({
bears: 0,
increasePopulation: () => set((state) => ({ bears: state.bears + 1 })),
removeAllBears: () => set({ bears: 0 }),
}))
const MyContext = createContext<typeof store | null>(null)
export const Provider = ({ children }: { children: React.ReactNode }) => (
<MyContext.Provider value={store}>{children}</MyContext.Provider>
)
export const useMyStore = (selector: (state: State) => unknown) => {
const store = useContext(MyContext)
if (!store) throw new Error('useMyStore must be used within a Provider')
return useStore(store, selector)
}
// create ver.
import { createContext, useContext } from 'react'
import { create, useStore } from 'zustand'
type State = {
bears: number
increasePopulation: () => void
removeAllBears: () => void
}
const store = create<State>((set) => ({
bears: 0,
increasePopulation: () => set((state) => ({ bears: state.bears + 1 })),
removeAllBears: () => set({ bears: 0 }),
}))
const MyContext = createContext<typeof store | null>(null)
export const Provider = ({ children }: { children: React.ReactNode }) => (
<MyContext.Provider value={store}>{children}</MyContext.Provider>
)
export const useMyStore = (selector: (state: State) => unknown) => {
const store = useContext(MyContext)
if (!store) throw new Error('useMyStore must be used within a Provider')
return store(selector)
}
결론
저번에 고민했던 내용을 해결할 수 있을 것 같다.
내일 할 일
- gloddy 회의 및 개발