reactjs - איך אני יוצר מכסה של hook ב-Typescript לבוחר חנות של Zustand


אני מנסה להשתמש ב-Zustand כחלופה ל-React Context כדי לספק מצב משותף בין תת-קבוצה של רכיבים, ואחד הדפוסים שאני מוצא את עצמי משתמש בו רבות הוא הסלקטור הרדוד עם תכונות מרובות, כך:

// store.ts
interface State {
  data: object,
  setData: (newData: State['data']) => void,
}

const useStore = create<State>(set => ({
  data: {},
  setData: (data) => set({ data }),
});


// Component.tsx
import shallow from 'zustand/shallow';
import useStore from './store.ts';

const { data, setData } = useStore(
  ({ data, setData }) => ({ data, setData }),
  shallow
);

// Use 'data' and 'setData'

ההבנה שלי היא שאני צריך להשתמש בבדיקת השוויון shallow כשעושים סוג כזה של בורר מולטי-תכונות, אבל ברור שזהו דפוס מאוד מפורט לכתוב את המפתחות כמה פעמים ותמיד להוסיף את האפשרות shallow, במיוחד אם מדובר ביותר ממפתח אחד או שניים.

אני רוצה ליצור hook עוטף עבור useStore שיקח פשוט רשימת מפתחות ויטפל בשאר זה עבורי, כך:

// store.ts
import pick from 'lodash/pick';

const useStoreState = (keys: (keyof State)[]) =>
  useStore(state => pick(state, keys), shallow)

// Component.tsx
import { useStoreState } from './store';

// Ideally the return value here has the same type as the example above
const { data, setData } = useStoreState(['data', 'setData']);

זה עובד בסדר גמור (לפחות אני חושב שכן - אני לא יודע בוודאות אם ה-pick שוברת את מנוי הסלקטור), אבל אני פשוט לא מצליח לגרום להקלדה לעבוד נכון.

הסוגים של Zustand מורכבים למדי ומבצעים הרבה מסקנות, אבל האם מישהו יודע דרך להשיג זאת? האם אני מפספס גישה אחרת כדי להתמודד עם הבעיה הזו?

לחיים!

תשובה #1

הייתי מציע את היישום הבא (שיש לו תחביר מעט שונה משלך, אבל הוא גם פחות מפורט):

// Utility function, to allow us to pick fields from the store
const useMulti = <T extends object, K extends keyof T>(
  useStoreFn: UseBoundStore<StoreApi<T>>,
  ...items: K[]
): Pick<T, K> => {
  return items.reduce(
    (carry, item) => ({
      ...carry,
      // No need to use useShallow here, as we fetch the objects one by one
      [item]: useStoreFn((state) => state[item]),
    }),
    {}
  ) as Pick<T, K>;
}

אז, העטיפה:

// Wrapper store hook
const useStoreState = (...items: Array<keyof State>) =>
  useMulti(useStore, ...items)

אז בסופו של דבר, אתה יכול לגשת לחנות שלך עם הדברים הבאים:

const {data,setData} = useStoreState("data","setData")

אתה יכול לבדוק את הדוגמה החיה הזאת שעשיתי אם אתה רוצה לשחק קצת