原标题:Can I use a Zustand store inside a React context to create multiple instances of the store?
I m trying to create a post component where each post has its own state. The post component is really complex, so it s necessary to use the React context hook.
import { createContext, useContext, PropsWithChildren } from "react";
import { create, StoreApi, UseBoundStore } from "zustand";
// Define the type of the context
type LikesStore = {
count: number;
isLiked: boolean;
initialize: (initialCount: number) => void;
toggleLiked: () => void;
};
// Define the type of the context
type LikesContextType = UseBoundStore>;
// Create the context
const likesContext = createContext(undefined);
// Create a hook to use the context
const useLikesContext = () => {
const context = useContext(likesContext);
if (context === undefined) {
throw new Error("useLikesContext must be used within a LikesProvider");
}
return context;
};
// Create a provider
const LikesProvider = ({ children }: PropsWithChildren) => {
// Zustand store
const useLikesStore = create((set) => ({
count: 5,
isLiked: false,
initialize: (initialCount) => set({ count: initialCount }),
toggleLiked: () =>
set((state) => ({
isLiked: !state.isLiked,
count: state.isLiked ? state.count - 1 : state.count + 1,
})),
}));
return (
{children}
);
};
export { LikesProvider, useLikesContext };
Here s how it s used in different components within the Post component:
function Counter() {
const { count } = useLikesContext()();
return (
{count} likes
);
}
function LikeButton() {
const { toggleLiked, isLiked } = useLikesContext()();
return (
);
}
Is this approach appropriate, or should I revert to using useState or useReducer? Because I m leaning toward the Zustand approach because it suits my preferences better.
最佳回答
You can, but your LikesProvider will create a new store each time you render it. You should also consider using the useStore hook in useLikesContext, rather than just extracting the whole store.
N.b. zustand/context` mentioned in @Oktay s answer is deprecated, and will be removed in v5
Adapting the documentation example:
const LikesProvider = ({ children }: PropsWithChildren) => {
const ref = useRef(create((set) => ({
count: 5,
isLiked: false,
initialize: (initialCount) => set({ count: initialCount }),
toggleLiked: () =>
set((state) => ({
isLiked: !state.isLiked,
count: state.isLiked ? state.count - 1 : state.count + 1,
})),
})));
return (
{children}
)
}
type UseLikesSelect = Selector extends (state: LikesStore) => infer R ? R : never
const useLikesContext = any>(selector: Selector): UseLikesSelect => {
const store = useContext(LikesContext)
if (!store) {
throw new Error( Missing LikesProvider )
}
return useStore(store, selector)
}
Which you would then use in components like
function Counter() {
const count = useLikesContext(s => s.count);
return (
Zustand has its own Provider functionality. zustand/context
https://docs.pmnd.rs/zustand/previous-versions/zustand-v3-create-context
From the example:
import create from zustand
import createContext from zustand/context
const { Provider, useStore } = createContext()
const createStore = () => create(...)
const App = () => (
...
)
const Component = () => {
const state = useStore()
const slice = useStore(selector)
...
If it does not fit you, you can use your implementation as well. With few changes.
If you create a store inside a component, you have to memoize it, in order to create it only once and not on each render.
const useLikesStore = useMemo(() => create(...), []) // create the store only once
Better change your custom hook into this:
const useLikesContext = (selector) => { // use a selector
const useStore = useContext(likesContext);
if (useStore === undefined) {
throw new Error("useLikesContext must be used within a LikesProvider");
}
return useStore(selector); // call it here, instead of returning the hook
};
It is a hook, that returns another hook. This ensures that the returned hook will be called only at top level.
const count = useLikesContext((store) => store.count);
I don t see selectors in your example. If you don t use them, no need to use zustand, context will do the same thing.
This is my first question, and english is not my first language, sorry if my question is hard to understand
I was trying to make simple CRUD app with mysql database and react as the frontend, and i ...
I have two react apps, parent app and child app. and child app have an hash router.
I have build the child app using npm run build, It creates build folder.
That build folder moved into inside the ...
I have this custom filter for date , filter button is working as expected but reset button is not working, can anyone help me,what s wrong here?
Below is my code which contain handlesearch,handlereset ...
I am using react. I want to add a line break <br> between strings
No results and Please try another search term. .
I have tried No results.<br>Please try another search term.
but ...
I am trying to make a POC with Rails5, action Cable, React and Rails and React DnD.
The purpose is to make an app like trello but for an recruitment process.
My front is in ReactJS.
I have 3 ...