ค้นหาเว็บไซต์

reactjs - ฉันจะสร้างตัวห่อ hook ตัวเลือกของร้าน Zustand ใน Typescript ได้อย่างไร


ฉันกำลังพยายามใช้ Zustand แทน React Context เพื่อให้มีสถานะที่แชร์ร่วมกันระหว่างชุดย่อยของคอมโพเนนต์ และรูปแบบหนึ่งที่ฉันพบว่าตัวเองใช้บ่อยคือ selector แบบตื้นที่มีหลายคุณสมบัติ ดังนี้:

// 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")

คุณสามารถตรวจสอบตัวอย่างสดนี้ที่ฉันทำได้ถ้าคุณต้องการลองเล่น