Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Zustandを用いた実践的状態管理

Avatar for Nokogiri Nokogiri
July 17, 2025
20

 Zustandを用いた実践的状態管理

Avatar for Nokogiri

Nokogiri

July 17, 2025
Tweet

Transcript

  1. 1. Actions に状態更新ロジックを集約する const useStoreStockDialogStore = create<StoreStockDialogStore>()((set) => ({ actions:

    { updateStoreStockReason: (reason) => { set((state) => ({ ...state, // プライマリ状態の更新 storeStockInfoFormValues: { ...state.storeStockInfoFormValues, storeStockReason: reason, // 他の状態への副作用 counterPartyId: INITIAL_FORM_VALUES.counterPartyId, counterPartyName: INITIAL_FORM_VALUES.counterPartyName, }, stockOperationConfig: { ...state.stockOperationConfig, counterParty: null, }, })); }, }, })); Zustandを用いた実践的状態管理 2025/07/24 - Offers Tech Event 10
  2. 2. セレクターによる効率的な状態参照 // selectors.ts export const selectFeeAmount = (state: StoreStockDialogStore)

    => state.storeStockInfoFormValues.feeAmount; // Component const feeAmount = useStoreStockDialogStore(selectFeeAmount); 状態の参照を一箇所に集約 Stateのデータ構造を変えてもコンポーネント側に影響を出さない 純粋関数なのでテストしやすい Zustandを用いた実践的状態管理 2025/07/24 - Offers Tech Event 11
  3. 3. useShallow を使った配列への浅い参照 const selectMedicineIds = (state: StoreStockDialogStore) => state.medicineInfoList.map((i)

    => i.medicineId); function MedicineList() { const ids = useStoreStockDialogStore(useShallow(selectMedicineIds)); return ( <ul> {ids.map((id) => ( <MedicineListItem key={id} medicineId={id} /> ))} </ul> ); } 配列の内容が変わらなければ再描画を防ぐ。パフォーマンスの向上 createSelector でも代替可能 Zustandを用いた実践的状態管理 2025/07/24 - Offers Tech Event 12
  4. 4. 末端コンポーネントでの状態参照 function MedicinePrice() { const medicinePrice = useStoreStockDialogStore(selectMedicinePrice); return

    ( <input type="text" value={medicine.price} /> ) } 必要な状態のみを参照 不要な再描画を防ぐ Zustandを用いた実践的状態管理 2025/07/24 - Offers Tech Event 13
  5. 5. Store のライフサイクル管理 // StoreProvider.tsx export const StoreProvider = ({

    children }: { children: ReactNode }) => { const storeRef = useRef<StoreApi<StoreStockDialogStore>>(); if (!storeRef.current) { storeRef.current = createStoreStockDialogStore(); } return ( <StoreContext.Provider value={storeRef.current}> {children} </StoreContext.Provider> ); }; Initialize state with props React コンポーネントのライフサイクルと連動 Stateの破棄漏れを防ぐ Zustandを用いた実践的状態管理 2025/07/24 - Offers Tech Event 14
  6. 6. immer を利用した安全な更新 const useStore = create<Store>()( immer((set) => ({

    nested: { value: 0 }, actions: { updateNested: (value) => { set((state) => { state.nested.value = value; // 直接代入可能 }); }, }, })) ); 不変性を保ちながら直感的な更新 バグの減少 Zustandを用いた実践的状態管理 2025/07/24 - Offers Tech Event 15
  7. 7. Zod と組み合わせたバリデーション const selectStoreStockInfoErrors = (state: StoreStockDialogStore) => {

    const result = storeStockInfoFormSchema.safeParse( state.storeStockInfoFormValues ); return result.success ? null : result.error.flatten(); }; // Component const errors = useStoreStockDialogStore(selectStoreStockInfoErrors); 型安全なバリデーション リアルタイムエラー表示 Zustandを用いた実践的状態管理 2025/07/24 - Offers Tech Event 16
  8. 18

  9. 19