Replies: 28 comments 2 replies
-
... to add to my question and make it more clear, the with-zustand Next.js example README also says:
So what I'm looking for is the exact opposite - i.e. I don't want the same store to be used, "even between page changes". So, I need the following workflow:
Is this something that'd be easy to achieve with zustand? |
Beta Was this translation helpful? Give feedback.
-
@Munawwar or anyone? |
Beta Was this translation helpful? Give feedback.
-
Full example at https://codesandbox.io/s/nextjs-with-zustand-354-forked-bryjr?file=/lib/store.js I've forgotten to update the next.js repo with the last change in interface, but the code is supposed to also be at https://github.com/vercel/next.js/tree/canary/examples/with-zustand |
Beta Was this translation helpful? Give feedback.
-
Oh wait, you don't want to use the same store between pages on client side? I haven't tried it yet, but maybe you can create new context inside App, but you will need to keep a global reference somewhere so that consumers can import the correct useStore() hook? |
Beta Was this translation helpful? Give feedback.
-
@Munawwar I can't understand what you mean. Could you try in different words? |
Beta Was this translation helpful? Give feedback.
-
@meglio Ok I tried my initial idea. It didn't work. The only way with our current context approach is to reset all the states inside the same store. https://codesandbox.io/s/nextjs-with-zustand-test-5nk81?file=/lib/store.js:1566-1807 |
Beta Was this translation helpful? Give feedback.
-
I don't know if its the exact thing you are looking for, but i use several stores in my pages based on need. |
Beta Was this translation helpful? Give feedback.
-
@goupilAnthony it's not what I was asking about, so you should have misunderstood. |
Beta Was this translation helpful? Give feedback.
-
This sounds like you don't need any benefits from a store and therefore don't need Zustand. If you want to start from scratch each request, create an object in getServerSideProps or getInitialProps. |
Beta Was this translation helpful? Give feedback.
-
Wrong. I am using the benefits from a store and I do need Zustand. Otherwise I'd be using Context or something like that. Please let's stick to solving the problem I described, I'm not asking whether using Zustand is practical in my case or not. Many thanks. |
Beta Was this translation helpful? Give feedback.
-
Nice attitude towards people who are trying to help you. You'll go far. Rather than simply asking for people to do your R&D, perhaps show us what you've attempted then elaborate on what exactly it is you want. Perhaps someone with more tolerance than me will help you. |
Beta Was this translation helpful? Give feedback.
-
I do see a global state manager being useful even when app is mostly client-side. There are even some using next.js like an SPA with zustand (famous one is Tanner Linsley, creator of react-query). So.. let's continue with the initial question. The reason why the flow gets difficult is because on client-side with next.js, page navigation does not clear _app's local states, rather tries to "hydrate" it's states (regardless of whether the page you are navigating to was built for SSR/SSG or not). As mentioned, with the current API, the only way I could achieve what OP is looking for, is by replacing the contents of existing store on page navigation - https://codesandbox.io/s/nextjs-with-zustand-test-5nk81?file=/lib/store.js:1566-1807 If it doesn't work out, and unless someone (with more experience with next) can come up with a better solution that fits with the current API, a better solution would be to change the API to be more like (forgive the shameless plug), another state manager I've written react-global-states, where hooks are not passed through the provider. But that is a breaking change, and we would have to evaluate carefully. |
Beta Was this translation helpful? Give feedback.
-
@billymcintosh , it is in the very beginning of this thread, in my first message. Here is what I need:
... and then in the next message:
So I'm not asking anyone to do my R&D. I know exactly what I need. I don't know what is the right (canonical) way to do it with Zustand. P.S. And this does not sound like any help anyway: "This sounds like you don't need any benefits from a store and therefore don't need Zustand." |
Beta Was this translation helpful? Give feedback.
-
You are asking for functionality that doesn't exist. In fact: -
... of what Zustand & Next.js do. We all love a coding challenge but forcing software to do the opposite of what it's intended is a code smell and most likely a hacky solution. Use a POJO, fork Munawwar's code or post what you've got up to so the community can help with this unique edge case. |
Beta Was this translation helpful? Give feedback.
-
How is it an edge case? I do have a working solution, and its logic is similar to what @Munawwar does. I just don't like the approach - it sounds like a workaround rather than a canonical way to have a global state per page. Hence asking. |
Beta Was this translation helpful? Give feedback.
-
It is a workaround, no doubt (and it doesn't look clean). |
Beta Was this translation helpful? Give feedback.
-
I'm not 100% following, but from:
What I can say is:
|
Beta Was this translation helpful? Give feedback.
-
@Munawwar can you provide me your example in typescript that could be helpful |
Beta Was this translation helpful? Give feedback.
-
@dai-shi so, I'm not suggesting to make Zustand more opinionated. I'm just saying we could try improve the API as to make the problem described above easily solvable. I still think the problem I described is not only a legit one, but also not specific to Next.js - same problem exists with any single-page applications, where the state is to be shared between components on a page, but not between pages. There should be a way to achieve it without ugly workarounds. It should not affect how the existing features work. I love the library and I'm using it. It just turned out that for the category of problems that I described above, it is very verbose to achieve simple logic described as "state state between components but not between pages". |
Beta Was this translation helpful? Give feedback.
-
Now, I'm afraid if I understand the problem or not. |
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
I'm not sure how the store is initialized, but |
Beta Was this translation helpful? Give feedback.
-
@dai-shi is correct, it doesn't have to be a hook. By doing useStore.getState() you then have access to any objects or actions. This is how it works with vanilla js. |
Beta Was this translation helpful? Give feedback.
-
Maybe I can help with @meglio's question. If I understand correctly, the requirements are the following:
I don't have a lot of experience with Next.js, so I will describe the solution with a SPA. There are two solutions:
Solution 1: Global storesExample for page one: /* stores/pageOneStore.js */
import create from 'zustand'
export default useStore = create(set => ({
propertyOne: undefined,
setPropertyOne: (propertyOne) => set({ propertyOne }),
reset: () => set({ propertyOne: undefined }, true)
// other properties and actions...
}))
/* pages/PageOne/components/PageOneChild.jsx */
import useStore from '../../../stores/pageOneStore'
function PageOneChild () {
// Use the store in child components
const propertyOne = useStore(state => state.propertyOne)
return (<div>{propertyOne}</div>)
}
/* pages/PageOne/index.jsx */
import useStore from '../../stores/pageOneStore'
function PageOne () {
// When this page is loaded, write your data into the store.
// This can be done via e.g. a simple useEffect
const setPropertyOne = useStore(state => setPropertyOne)
useEffect(() => {
const data = loadData()
setPropertyOne(data.propertyOne)
}, [])
// Reset the store on unmount (e.g. when the user navigates)
const reset = useStore(state => reset)
useEffect(() => {
return () => reset()
}, [])
return (<div><PageOneChild /></div>)
} Use the same approach for as many other pages as you want. Solution 2: Stores with ProvidersIf you want prohibit pages and their children to access the stores of the other pages, you can use Providers. Here are code examples for using zustand with Providers: https://github.com/pmndrs/zustand#react-context I hope I could help with your problem. |
Beta Was this translation helpful? Give feedback.
-
Hi @schmuecker , please note that it's not just per page, it's per page per user (each user will have its own data in each store per page). Should your solution still work in this scenario? |
Beta Was this translation helpful? Give feedback.
-
@meglio sure, if you make an authenticated request, the user receives their specific data. |
Beta Was this translation helpful? Give feedback.
-
@jp185357 Did you find a solution? |
Beta Was this translation helpful? Give feedback.
-
Wow just wow. I understand the community is trying hard to help, but also it is so funny to se how much eveyone is struggling to understand the very basic web dev concepts, including OP. What he is asking for is a state reset on page navigation. In next, its called a page, in react spas a tab. Whatever you call it it is “reset on navigation”. It is not the same as browser navigation, which resets the window, and thus creates a new zustand automatically.
OP doesn’t want that. They want the zustand state to be reset when a navigation event occurs. Afaik there is no easy solution for this - a spa navigation is a fake navigation and needs a fake solution - other than making a useeffect that listens to any navigation in the app and resets the state explicitly by calling useMyStuff()’s reset method. This has been pointed out by the community in this thread. What OP said (even tho their wording is a bit aggressive, possibly due to an avalanche of well meaning - but ultimately empty answers) is that it could be super useful if Zustand was expanded so that a store’s fate can (optionally) be tied to a component instead of a window. You’d create a store on the component (perhaps context), in the same way as you do with useMemo in a context. All the children get some nice zustand benefits without being global. Once the navigation happens and context unmounts and remounts, a new fresh zustand store will be created. All the current patterns (that I’ve seen) that employ a context only store the global reference to zustand, not the actual value, he wants an option to do that - to attach zustand to a variable instead of window. It is a very good idea, and would expand the usage of zustand onto new avenues. I don’t think its currently doable, we can’t store zustand into a variable, we can only store a reference toward the global object. Zustand’s value isn’ that its global, its main value is the ease of use and performance of selective subscribers. The OP would like to keep those benefits while losing the “globality”. |
Beta Was this translation helpful? Give feedback.
-
Next.js example with-zustand says:
Could you please provide a canonical example of using zustand in Next.js with that exact approach - i.e. a fresh client-side only store per page?
-- Many thanks,
Anton
Beta Was this translation helpful? Give feedback.
All reactions