Which state management library does Vercel/Next.js recommend?
Unanswered
African Slender-snouted Crocodil… posted this in #help-forum
African Slender-snouted CrocodileOP
I'm doing some research and found out that there are several libs to choose from:
- redux
- zustand
- mobx
- jotai
- recoil
- valtio
- little state machine
Question 1: Which ones work with app router?
Question 2: Which ones work with SSR?
Question 3: Which ones does Vercel/Next.js recommend its users?
- redux
- zustand
- mobx
- jotai
- recoil
- valtio
- little state machine
Question 1: Which ones work with app router?
Question 2: Which ones work with SSR?
Question 3: Which ones does Vercel/Next.js recommend its users?
85 Replies
- I guess most of them should work (Check individual libraries)
- They should work with SSR.
- Vercel/Next.js won't recommend any to users BUT I recommend redux-toolkit
- They should work with SSR.
- Vercel/Next.js won't recommend any to users BUT I recommend redux-toolkit
from your question 1, 2 I feel you have some misconception about SSR/App router
Personally I'm partial to zustand, but I agree with james above
You don't use state serverside
Can you tell us a bit more about your use case?
slightly related, but https://xyproblem.info/
@Lukas Personally I'm partial to zustand, but I agree with james above
I heard about Zustand much but never get a chance to try it.
if you have experience with both, can you briefly tell me about pros and cons of zustand vs redux tool kit?
if you have experience with both, can you briefly tell me about pros and cons of zustand vs redux tool kit?
as I couldn't find anything painful from redux toolkit
@Lukas
@James4u I heard about Zustand much but never get a chance to try it.
if you have experience with both, can you briefly tell me about pros and cons of zustand vs redux tool kit?
I've never used redux tool kit. I think I've been on one project where redux was used, but I've found that zustand is simpler and easier to pick up. I believe zustand is also better optimized than redux (as in fewer rerenders).
The way I see it is as yup vs zod. They're both great, and (in most cases) you'll be fine no matter what one you pick
The way I see it is as yup vs zod. They're both great, and (in most cases) you'll be fine no matter what one you pick
But I'm probably not the best person to ask lol
@Lukas I've never used redux tool kit. I think I've been on one project where redux was used, but I've found that zustand is simpler and easier to pick up. I believe zustand is also better optimized than redux (as in fewer rerenders).
The way I see it is as yup vs zod. They're both great, and (in most cases) you'll be fine no matter what one you pick
regarding rerendering, in RTK, we use hooks like
useSelector
which allows us to pick a certain element of global state and the page only re-renders when that piece of global state changes.and yeah, there might be some complexity differences in the source code but anyway RTK is much simpler than original redux
Thats nice
Maybe I'll check it out in my next project, I always like experimenting
You should try zustand if you get a chance too, I quite like the api
sure, I really heard much about it - will try it for sure
American black bear
I am a big fan of
Jotai
, the least boilerplate out of all the options, similar to useState
, does the job pretty wellAmerican black bear
the only thing I like is that is so much simpler to setup and work with. There is no this thing: https://redux-toolkit.js.org/tutorials/typescript
you just create an atom and create a hook and the implementation comes to this:
you just create an atom and create a hook and the implementation comes to this:
// src/atoms/count.ts
import { atom, useAtom } from "jotai"
const countAtom = atom<number>(0)
export default function useCount() {
const [count, setCount] = useAtom(countAtom)
// custom functions related to state
function increment() {
setCount(prev => prev + 1)
}
return {count, setCount, increment}
}
okay then how can you make bridge between two hooks?
like the thunks in the redux toolkit
so let say, I have a bunch of states to be cleared when a user logs out
in redux toolkit, we have extraReducer which gets events from other thunks of slices - for example
logOut()
in this case and clear internal states on that eventwhat's the implementation like using jotai?
Spectacled bear
+1 for jotai. Fount it to be the simplest to work with.
and what about the data fetching with jotai?
RTK has builtin states and error handling inside it
Spectacled bear
If you want something that takes care of both state and data fetching, use something like react query or SWR
RTK uses react query internally
@Spectacled bear +1 for jotai. Fount it to be the simplest to work with.
simple
means you need more custom implementation for certain features@James4u what's the implementation like using jotai?
American black bear
something like this I guess:
but I have never encountered a problem like this in practice.
import { atom } from 'jotai'
// user session related atoms
const userAtom = atom(null)
const preferencesAtom = atom({ theme: 'light', language: 'en' })
const sessionAtom = atom(null)
const logoutAtom = atom(
null,
(get, set) => {
set(userAtom, null)
set(preferencesAtom, { theme: 'light', language: 'en' })
set(sessionAtom, null)
}
)
const useLogout = () => {
const resetUser = useUpdateAtom(userAtom)
const resetPreferences = useUpdateAtom(preferencesAtom)
const resetSession = useUpdateAtom(sessionAtom)
return () => {
resetUser(null)
resetPreferences({ theme: 'light', language: 'en' })
resetSession(null)
}
}
but I have never encountered a problem like this in practice.
@James4u `simple` means you need more custom implementation for certain features
Spectacled bear
It seems like you already have your preference
@Spectacled bear It seems like you already have your preference
yeah, I am not OP
😆 OP is the most inactive here
@James4u looks definitely clean
American black bear
is that sarcastic... :D I just cannot read the redux toolkit syntax for some reason :D
if they tried to solve only state management it could be more simpler but as I said before it's not only about global state management. it includes react-query, error handling & built-in states for data fetching and caching.
African Slender-snouted CrocodileOP
Hey all, thanks for the replies..
I was actually playing around with little-state-machine in a new Next.js 14 app and got stuck:
https://github.com/beekai-oss/little-state-machine/issues/151
My use case:
I'm building a wizard/multi-step form. I need to be able to persist form state. It's basically age, and then 9 different radiobutton values. When the user refreshes the page either by clicking the refresh button in his/her browser, or if he/she need to log in/sign in (full refresh required) the form state should persist and the fields should be populated automatically - the user should not need to redo those questions he/she already filled in.
I was reading on the RTK docs and they state that if you don't need global state then you're better off with e.g. React Context API. Which is what LSM is a wrapper around.
I was actually playing around with little-state-machine in a new Next.js 14 app and got stuck:
https://github.com/beekai-oss/little-state-machine/issues/151
My use case:
I'm building a wizard/multi-step form. I need to be able to persist form state. It's basically age, and then 9 different radiobutton values. When the user refreshes the page either by clicking the refresh button in his/her browser, or if he/she need to log in/sign in (full refresh required) the form state should persist and the fields should be populated automatically - the user should not need to redo those questions he/she already filled in.
I was reading on the RTK docs and they state that if you don't need global state then you're better off with e.g. React Context API. Which is what LSM is a wrapper around.
BTW, I will only need to persist this form state for a particular route and not for the entire app.
So I don't think I need full-blown state management like RTK or Zustand.
Please correct me if I'm wrong
@James4u yeah, I am not OP
Spectacled bear
lmao I thought you were for some reason. my bad.
African Slender-snouted CrocodileOP
Lastly, I'm thinking keep it simple and store the form values in localStorage. I think those are all the requirements.
@Spectacled bear lmao I thought you were for some reason. my bad.
because I was more active than OP 😂
@African Slender-snouted Crocodile Lastly, I'm thinking keep it simple and store the form values in localStorage. I think those are all the requirements.
NOPE!!!! @African Slender-snouted Crocodile localstorage is not for global state management
RTK has difficult learning curve
African Slender-snouted CrocodileOP
@James4u i don't think I need global state management... I just need to persist a couple of form values for a particular route
I think React Context API will do?
yeah, then go with context
Spectacled bear
Their use case of persisting populated fields on refresh is a bit strange though
African Slender-snouted CrocodileOP
well you never know... a user fills in a form... goes out for lunch (closes his/her browser)... comes back.. reopens that same route...
Spectacled bear
context api would not work in that instance, right?
African Slender-snouted CrocodileOP
context that uses localStorage as store
@African Slender-snouted Crocodile well you never know... a user fills in a form... goes out for lunch (closes his/her browser)... comes back.. reopens that same route...
well, it's not an issue losing input form unless it's an important onboarding steps
African Slender-snouted CrocodileOP
is what im thinking..
if you really want to store those data, you might think again - what if others visit through their phone?
African Slender-snouted CrocodileOP
well, I guess it depends... but if it's let's say 100 questions and you filled out 99 then it would suck to have to do them all 99 over again
okay then save them in the database
@James4u if you really want to store those data, you might think again - what if others visit through their phone?
African Slender-snouted CrocodileOP
that is a possibilty but very unlikely
@African Slender-snouted Crocodile well, I guess it depends... but if it's let's say 100 questions and you filled out 99 then it would suck to have to do them all 99 over again
you don't want to answer 99 questions again when you visit through your phone?
African Slender-snouted CrocodileOP
in a db? and pay extra for server cost? for 10 fields that can be stored in the browser?
im trying to keep it simple
I only feel I wasted my time, thank you
African Slender-snouted CrocodileOP
how so?
@African Slender-snouted Crocodile in a db? and pay extra for server cost? for 10 fields that can be stored in the browser?
everyone in this thread is to help you - and I have been asking questions as you didn't provide the context exactly.
keep your manner man
keep your manner man
African Slender-snouted CrocodileOP
what do you mean? where? what have i said?
i gave you a thumbs up didnt i?
@African Slender-snouted Crocodile in a db? and pay extra for server cost? for 10 fields that can be stored in the browser?
Spectacled bear
Are those fields never going to be stored after they finish filling out the form?
African Slender-snouted CrocodileOP
@Spectacled bear no, it's not needed. It's just a quiz.
Spectacled bear
The it seems you already have your answer. Just use local storage. Most state libraries support storing in local storage
@Spectacled bear The it seems you already have your answer. Just use local storage. Most state libraries support storing in local storage
African Slender-snouted CrocodileOP
I was thinking about going with https://docs.pmnd.rs/zustand/guides/nextjs but I'm not sure it's right for my app.. also, next.js requires so many extra steps 😦
lol
@African Slender-snouted Crocodile I was thinking about going with https://docs.pmnd.rs/zustand/guides/nextjs but I'm not sure it's right for my app.. also, next.js requires so many extra steps 😦
Spectacled bear
Well you have lots of suggestions already in this thread. Not much we can do for you anymore.
African Slender-snouted CrocodileOP
Maybe this is all I need? (from ChatGPT ^^)
import React, { createContext, useState, useEffect } from 'react';
// Create a context
const FormContext = createContext();
// Create a provider component
const FormProvider = ({ children }) => {
const [formData, setFormData] = useState(() => {
// Get initial state from localStorage if it exists, otherwise use default values
const savedFormData = localStorage.getItem('formData');
return savedFormData ? JSON.parse(savedFormData) : { age: '', gender: '' };
});
useEffect(() => {
// Update localStorage whenever formData changes
localStorage.setItem('formData', JSON.stringify(formData));
}, [formData]);
return (
<FormContext.Provider value={{ formData, setFormData }}>
{children}
</FormContext.Provider>
);
};
export { FormContext, FormProvider };
Cuban Crocodile
I use zustand because it’s easy. But for what you said, if it comes to persisting data I don’t think we’ll talk about server again
@James4u RTK uses react query internally
I have to correct you but AFAIK it does not. Look at this comarion of RTK-query v react-query v others that Redux Toolkit team have made:
https://redux-toolkit.js.org/rtk-query/comparison
RTK query is a very different beast in my experience to react-query. I have a (non-next.js) app that uses redux rtk for a lot of stuff, so adding rtk-query was simple. If I didn't have redux rtk already in the project, I probably would have used a dedicated remote data library like react-query.
But of course all cases are different, and using rtk with react-query can be helpful for some.
https://redux-toolkit.js.org/rtk-query/comparison
RTK query is a very different beast in my experience to react-query. I have a (non-next.js) app that uses redux rtk for a lot of stuff, so adding rtk-query was simple. If I didn't have redux rtk already in the project, I probably would have used a dedicated remote data library like react-query.
But of course all cases are different, and using rtk with react-query can be helpful for some.
@African Slender-snouted Crocodile Maybe this is all I need? (from ChatGPT ^^)
import React, { createContext, useState, useEffect } from 'react';
// Create a context
const FormContext = createContext();
// Create a provider component
const FormProvider = ({ children }) => {
const [formData, setFormData] = useState(() => {
// Get initial state from localStorage if it exists, otherwise use default values
const savedFormData = localStorage.getItem('formData');
return savedFormData ? JSON.parse(savedFormData) : { age: '', gender: '' };
});
useEffect(() => {
// Update localStorage whenever formData changes
localStorage.setItem('formData', JSON.stringify(formData));
}, [formData]);
return (
<FormContext.Provider value={{ formData, setFormData }}>
{children}
</FormContext.Provider>
);
};
export { FormContext, FormProvider };
For a simple case of persisiting form data for a specific user that survives between browser refreshes AND is only stored client side, then keeping filled in form data in localStorage seems ok and this implementation is also ok.
African Slender-snouted CrocodileOP
@Laustin Spayce thanks, i think I will look at litte state machine again, pick the parts i need from the source code, and fuse that with what chatgpt suggested.
@African Slender-snouted Crocodile I was thinking about going with https://docs.pmnd.rs/zustand/guides/nextjs but I'm not sure it's right for my app.. also, next.js requires so many extra steps 😦
I personally really like zustand, but for a small form wizard, I think you could just use formik and it's built in apis