reactjs - Πώς θα δημιουργούσα ένα wrapper hook επιλογέα καταστήματος Zustand σε Typescript
Προσπαθώ να χρησιμοποιήσω το 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, ειδικά αν είναι περισσότερα από ένα ή δύο κλειδιά.
Θα ήθελα να δημιουργήσω ένα wrapper 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")
Μπορείς να δεις αυτό το ζωντανό παράδειγμα που έκανα αν θέλεις να πειραματιστείς
