Options for managing non-persistent state
Hello, I am wondering how everyone manages their app state? (Context: next js app with convex and clerk auth)
With convex I don't have to worry about managing most of my state & it's realtime (amazing)
However how do you manage global state that is not related to / stored in the database? Does convex have any helpers for this?
For example: Let's consider we want to support dark+light mode in our app and we don't want to persist this info in convex, how should we do this with convex? are there any examples/tutorials related to this?
Another example could be toggling sidebar - from various different components, how should we go about this?
If possible, I'd prefer not to use any state management lib for this.
9 Replies
I have a pretty complex application and I only use Convex and React's state management utilities, specifically
useState
and contexts (no reducers). In most cases useState()
captures state well for a compoent and it's children. If state is more widespread, like your dark/light mode example, you may want to store it in a context so any component can hook in.
I have not identified any pain points with this approach, and I love the simplicity.I recommend checking out Jotai - while it can be considered a state management lib, it's extremely simple and lightweight - essentially it's like a globally accessible useState. I use it for simple, non-critical state like a sidebar toggle as you describe. It also has convenient helpers for things like persisting state to localStorage, and is safe to use with SSR/Next.js etc.
Jotai does look like a nice set of abstractions. I don't use next or SSR, good points to consider there if you are.
Thank you @erquhart @deen
So it's either context api Or external libs for global state management.
Is there anything recommended by convex officially?
It's a bit out of scope for Convex how you handle your non-convex client state. I'm not aware of any official recommendations for that. Really comes down to your preference. Jotai looks like a really clean way to handle your examples, and would probably have a bit less boilerplate than React context.
Here's what a global state manager would look like in React without an external lib:
But dang I am now looking at the Jotai docs and thinking how nice it might be to (someday) get rid of my global contexts. Jotai looks to have optimizations that I don't, and that I'm unlikely to implement unless forced. Nesting contexts can be particularly helpful, but I barely use them that way, if at all.
Convex is a backend with some simple but powerful tools for querying and manipulating data in the front end - its solution would be to store this data in the database. Take a look at this article about presence: https://stack.convex.dev/presence-with-convex as well as the other posts on https://stack.convex.dev about working with session data. You could store this data in a row of keys/values tied to a session id. Querying/mutating a simple row with an index is very fast, and you could use optimistic mutations to make changes appear instant.
But I'd just use a simple Jotai atom. If you're concerned about needing an external lib, compared to the size of say, Clerk, the module size is negligible - a few kilobytes. I'm using it with the same Next/Convex/Clerk set up as you.
Implementing Presence with Convex
Some patterns for incorporating presence into a web app leveraging Convex, and sharing some tips & utilities I built along the way.
Stack
Bright ideas and techniques for building with Convex.
Amazing, thank you.
I don't understand why it's not more popular, it fits in as an extension to the React paradigm so neatly. Perhaps because the documentation is a bit sparse, or terms like "atoms" sounding scary.
You can implement isolated context using provider stores with jotai if you want to, but I've also never felt the need. I haven't really used it for much beyond some simple global useStates, but I'm currently experimenting with dynamically creating memoized atoms for values in a complex form, for easily maintaining persistence and limiting re-renders to the relevant input components.
I have used recoil in the past, was exploring https://github.com/pmndrs/zustand, looks like a pretty good solution for my usecase.
Will checkout jotai before finalizing one.