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")
คุณสามารถตรวจสอบตัวอย่างสดนี้ที่ฉันทำได้ถ้าคุณต้องการลองเล่น
