Did you already build nontrivial applications with it? Where does it shine? What are the cons? What did you try before, which didn't work for you?
Principal eng working with 3 teams on a ~500k loc React site here. After lots of experimentation, we’re just using React contexts.<p>- Redux is cool but there’s so much decoupling that it gets hard to read the code. New hires would take too long to start, TS types got crazy, it was too much.<p>- XState is very good for state machines… but you barely ever need that level of control. Most of the time understanding it ends up being overhead. We’ve had maybe one good case for using it in about 10 years.<p>- React’s contexts are minimum overhead and work very well with “jump to definition” functionality and TS types. You can choose to use a reducer if you want, or skip it if it isn’t appropriate.<p>YMMV of course. This is just us.
Good ol’ {}<p>Add anything you want to keep to it, store it in the window with
window.app = {}<p>You can mix local storage in with it too if you want to write a class that checks its existence with a key.<p>Why must state management need a complex solution?<p>I’m sick of frameworks and modes where they abstract away the simplicity of javascript in favor of their way which is very economically driven.
Been building in HTMX for the last month and I’m loving the new paradigm. This vid did a good job of explaining the shift. <a href="https://youtu.be/LRrrxQXWdhI" rel="nofollow">https://youtu.be/LRrrxQXWdhI</a><p>(Been using preact/react since 2016, angular/jquery before that)
My personal favorite is re-frame for ClojureScript. I have used it to build things like a LaTeX editor with live preview, electron app frontends, and web-apps. There are wrappers like Kee-frame that extend re-frame by linking the URLs query to the current state, making it possible for users to easily share URLs to different states of a single page app.<p>The cons are:<p>- A fair amount of work to make changes to the state side-effect free, but the documentation has a good tutorial on how to approach this.<p>- It's for ClojureScript, so it's a non-starter for organizations that will not consider anything outside of the mainstream.<p>I have also used Elm. If I recall correctly, Elm's state management paradigm was inspired by re-frame. I found writing JSON decoders in Elm to be demoralizing and tedious. Since the creator of the language was vehemently opposed to providing any real JSON support I decided to move to ClojureScript.
In React:<p>- Provided it is not an offline-first app, move as much state handling as possible out of the frontend<p>- use SWR or React Query for server state<p>- Keep pagination, filters, and other such options in your URL<p>- Hold state as local as possible. Only ever move state up if two or more branches of the tree need to be synchronised.<p>- Pass information down through props. That is what they are for. A little “prop drilling” is fine.<p>- Use CSS custom properties for theming<p>This gets you >95% of the way with very little complexity.<p>For the leftover pieces of global state like ‘isSidebarVisible’ I like Zustand because it is tiny both in bytes and concept.<p>I don’t like to use Context for state management because it litters the top-level with providers and causes unnecessary rerenders.<p>Avoid a single global store at all costs.
Zustand is great: <a href="https://github.com/pmndrs/zustand">https://github.com/pmndrs/zustand</a><p>It gets out of the way in terms of boilerplate, has a good solution for avoiding unnecessary re-renders, has tooling for deep state updates without messy syntax (immer) and strikes an overall good balance between powerful and easy to use. Cons might be that it is a bit more obscure so people might have to learn it. Also the learning curve is a bit steep. YMMV
Assuming you mean a web-based application, then all state via HATEOAS, and CSS or JS in the front-end is strictly a non-essential progressive enhancement.<p>This is for commercial reasons. Apps that depend on assets are crippled over low-bandwidth or otherwise unreliable connections, and frequently break in the presence of aggressive content blockers. I won't do that to my customers.
It was always MobX for me, I’ve built a few sites and React Native apps with it and found it extremely productive in exchange for some magic, but it could be seen as somewhat heavyweight compared to some more “modern” solutions. Jotai and Zustand are two that I want to investigate but not used them yet.
For 98% of projects? A global state object that gets passed down the component tree.<p>This can scale to much greater complexity before it becomes an issue than many are willing to admit.
I have been a react dev for 7 years and have loudly advocated against state management tools all that time. React already is a state management tool, designed to eliminate the need for complex global state. You only need external state management if you don't fully commit to the paradigm.
Recoil. It works well, I was new to React and just use React state vars, but there's too much complexity that builds up over time.<p>The app I'm building (<a href="https://inventai.xyz" rel="nofollow">https://inventai.xyz</a>) is non-trivial, especially the canvas. There hasn't been any cost or downside. Quick to learn and implement.
Personally I have enjoyed Pinia the most when working with Vue projects: <a href="https://pinia.vuejs.org/" rel="nofollow">https://pinia.vuejs.org/</a><p>It is simple (no need for lots of boilerplate code), reasonably performant, integrates with the browser Vue dev tools nicely and is just generally a pleasure to work with, especially because Vue does a few things better than React in my eyes - most notably, the hooks.<p>Pinia in particular also seems to generally get out of your way and doesn't enforce a particular architecture upon you. Want to add methods to the store to interact with an API and not have to think about that in your other components, merely call a method for initializing some data from the API that will take care of the store state? Sure! Want to do the opposite and only use the store for persisting data, regardless of where it's initialized? Go ahead. Want to have your components react to changes in the store? This will work with either approach.<p>This is subjective, of course, but personally that combination of tools has resulted in a pretty good development experience, in my eyes something like the following is a nice stack:<p><pre><code> - Vue 3 with Composition API (hooks)
- using SFC with <script setup> (takes care of some boilerplate)
- using Pinia for state management
- using PrimeVue or a similar component library (to have ready-made components for most needs)
</code></pre>
For React, I have to say that MobX was nice last I checked: <a href="https://mobx.js.org/README.html" rel="nofollow">https://mobx.js.org/README.html</a> though React's own Context functionality is also okay: <a href="https://reactjs.org/docs/context.html" rel="nofollow">https://reactjs.org/docs/context.html</a>
Thus far I’ve really enjoyed <a href="https://xstate.js.org/" rel="nofollow">https://xstate.js.org/</a>. It’s fantastic for ensuring that your application is in an expected state and to control transitions between states. When it’s overkill you can often just drop to useState for simple stuff.
react-query to handle server updating state and per component hooks for local state items.<p>react-query has hook wrappers that allow accessing data you've fetched once across multiple components.<p>Calling the refetch in one will update all components using that data.<p>It's clean and minimises the need to think about shared state
I think it depends if you are working on an app or on a library. In an app I would recommend to use Zustand or Jotai. If you prefer a Redux-like state management with a central store and actions to update it, go with Zustand, if you prefer a proxy-based atomic solution, go with Jotai. There might be situations in library code where it's useful to use React context but I would not use it in app code. It's too easy to use it wrong.
My native web components fetch their own state. They pass data to children via attributes and to parents via event bubbling. Very happy with this solution. Re-renders work using observableAttributes, which is part of the native component standard. It’s “just JavaScript” that everyone already understands and still avoids global state.<p>But while some of the UI I build is complex, I don’t build SPAs. If I did maybe this wouldn’t work as well.
These are the options I have used and tested heavily (only in React):<p>Redux:<p>- pros: framework to place different pieces of logic, makes it predictable once everyone is onboarded; boilerplate (actions, reducers, selectors, etc) makes it easier to avoid mistakes if you're not using TS<p>- cons: boilerplate adds a lot of friction that's not needed if you're using TS; debugging usually requires jumping through more files<p>XState:<p>- pros: what I said for Redux but on steroids<p>- cons: big setup (learning-wise); feels overkill 95% of the time<p>Context:<p>- pros: simple to understand and use (you expose values and setters via useContext); minimal setup (Provider and useContext)<p>- cons: you're still trapped inside React, your logic is inside a big component by default<p>Mobx:<p>- pros: keeps your logic out of React by default; you can export your model to another env and debug/test/play easily<p>- cons: most costly to setup (learning, config) out of all the options (redux with starter toolkit reduces the setup overhead)<p>I mainly use Context now as I port from Redux. Feeling the pain of not having an interactive model outside of my app views and want to get my team on Mobx.
I prefer sticking w/ the basics and using EventEmitter.<p><a href="https://speaker.app" rel="nofollow">https://speaker.app</a> has a UI I've been prototyping w/ this approach.
I like valtio, works w/ React or just js. Has subscribe, derive, and more.<p><a href="https://github.com/pmndrs/valtio">https://github.com/pmndrs/valtio</a>
At my employer we have developed our own state management solution on top of react-easy-state. It's a good solution for us, it matches the backend more closely and has some conventions that work for our model. I wouldn't necessarily recommend it for other apps.<p>For personal stuff I like recoil and jotai. They're similar in design. Super simple to start, easy to type, work with layers of complexity.
mobx-state-tree (<a href="https://mobx-state-tree.js.org/" rel="nofollow">https://mobx-state-tree.js.org/</a>)<p>Benefits of it over mobx is data normalization with references and JSON patches which allow you sync complex state easily. Typed models are also a plus.<p>Drawbacks are performance (see <a href="https://github.com/mobxjs/mobx-state-tree/issues/1267">https://github.com/mobxjs/mobx-state-tree/issues/1267</a>).<p>Previously was using immer, which I loved because of immutability but moved off since classes and OOP didn't feel as natural as in mst.<p>If I were to pick an alternative, might try redux with normalization <a href="https://redux.js.org/usage/structuring-reducers/normalizing-state-shape" rel="nofollow">https://redux.js.org/usage/structuring-reducers/normalizing-...</a>.<p>And if I were to build a state management tool, I would prioritize a library that has
- immutability
- JSON patches and snapshots
- data normalization with references
- schemas / models compatible with zod
Recoil for single page apps. As simple as context but more readable. For another app the url was used as a single source of truth, so kind of a global state. The components just called useQueryParams.<p>For multi page apps (e.g. with nextjs) I’ve never used a global state manager. Next-auth, useReducer and react query are enough until now.
The url is the state, everything happens in response to url changes and everything changes the url.<p>Before I tried calling functionality and updating the url in response to user actions but since the state has to be exactly the same if you paste the url into the browser I got rid of the direct response.
Similar to some strong sentiments in this thread, we don't use common state managements. Mainly because they doesn't suit our need and requires us to learn more unnecessary patterns.<p>My company is building app with quite a set of complex features and structure (e.g. stateful integration with game consoles, background custom upload protocol, varying lifetime of modules, etc).<p>- The state management we always come back to is closure-based objects.<p>- Styled as agents, rather than passive storage (e.g. redux store-like construct). Thus providing separation of concern both in type definitions and code execution scheduling (can't find better words for these :'))<p>- In house event utility is used by the agents to communicate outwards.<p>- Combine with useEffect, useState, useMemo, and our in-house event utility to "escape" React's lifecycle by default and selectively subscribe to events, thus avoiding unnecessary-rerenders problems.<p>- Designed to abstract its domain and expose its internal data via methods.<p>- Optionally be designed to allow both code reuse and object reuse. Allowing devs to share or to not share states. Common use case for object reuse is agents acting as background-service propagated via React Context. It works really well with React Context.<p>- Optionally self-managing via buffers and async loop. The buffer is not exposed to its consumer directly, and the async loop works on the buffer.<p>- Can be useful for dependency injections too.<p>- Well isolated and optionally injectable so that you can unit-test against it without import mocks.<p>A caveat, this pattern isn't as usable when written with pure JavaScript. We relies heavily TS on FP patterns supported by fp-ts and io-ts as well as IDE's auto-complete and jsdoc to unload a whole stuff off our mind.<p>We've sometimes evaluated common state management solution and often found them requiring us to remember more things, but it doesn't yield valuable abstraction. In fact, most state management is abstracting the wrong thing.
When you refer to frontend state management, I'm assuming you're talking about libraries like Redux, and are using something like React. Basically, storing state that cuts across the component hierarchy.<p>First of all, I would suggest minimizing it as much as possible! You can often get away with a combination of component local state and data fetching libraries like SWR (the one I use) and react-query (I've heard it's good but haven't used). Modern data fetching libraries support intelligent caching, cache invalidation, and even optimistic updates.<p>The vast majority of internal tools at Twitter (prev employer where we built internal tools) didn't need any state management at all outside of swr and component local state.<p>However there will be some cases where some sort of client side state management will be useful. In these cases I reach for jotai. It was one of the first state management solutions designed post React Hooks, so it feels much more natural than state management solutions where hooks were bolted on. Additionally, it doesn't suffer from some of the rough edges that similar libraries like Recoil have (like naming fatigue from all those string keys).<p>Btw, I only use a tiny subset of jotai. I don't use any of the persistence or async stuff.<p>So tl;dr:<p>1. Build your app with component local state and SWR only.<p>2. If this gets messy, refactor your component local state and SWR code to be abstracted away as reusable functions / hooks.<p>3. Only when there is a performance problem <i>or</i> a really convoluted component hierarchy that doesn't make much logical sense, consider adopting jotai, but only for the parts of your app state that are causing the issues.
More like a cache for back end data but it covers a lot of the use cases for front end state management.<p><a href="https://tanstack.com/query/v4" rel="nofollow">https://tanstack.com/query/v4</a>
I use a simple 4 point system for state management:<p><a href="https://github.com/prettydiff/wisdom/blob/master/state_management.md">https://github.com/prettydiff/wisdom/blob/master/state_manag...</a><p>I use it for an OS GUI here which fully loads in 200ms in Chrome (300ms Edge):<p><a href="https://github.com/prettydiff/share-file-systems">https://github.com/prettydiff/share-file-systems</a><p>When simple things, like state management, become complicated they are either over engineered or poorly planned.
I remember I didn't have any concerns with state management when I was using emberjs. not sure why.<p>Now, working with react, I have successfully avoided redux and any extra state management like yhe plague.<p>Good abstractions, hook factories (under-disscussed topic imho), some sparse contexts. So far it has worked out great. I recently managed to implement quite complex requirements using these disciplines on a project while some other part of the same project contains redux-hell to do some simpler things
React specific but i’ve built a couple non-trivial applications with Recoil. I enjoy the ergonomics of it and building up a state graph. At its simplest it like a global version of useState which is really all you need, something you’re used to but happens to be shared. I prefer things that have simple primitives that can be composed into something complex. The documentation is good for describing what it does but not the best at easing you into it’s mental model.
At work when I was on the front end side( our company uses Angular(honestly its dope, it should be more popular IMO) ) and we settled with ngrx(a redux clone), which was fine until I used react hooks & context for my own side projects. I work for a major airline so I guess ngrx is a nice to have for a multi page multi state SPA but seriously there is way to much boiler code with ngrx/redux.
Svelte stores. Mainly because the docs are practical and not a lecture about state management or functional programming and secondly because stores come with Svelte.<p>React seems to be drowning in its own complexity these days. As another poster points out you can do global state by observing an object on ‘window’, that most react state management tools make this more complex rather than simpler is concerning.
xState<p>Sometimes you really need a state machine and for me this is the go to library.<p>Pros:<p>-Visualizer. Non-tech people love the visualizer. Tech people as well really.<p>-Integrates easily with entities which are also implicitly state machines, like Promise.<p>Cons:<p>-Learning curve. I've already rewritten our state machine once because my original implementation was not idiomatic.<p>Mobx also works. Ngrx, Redux and the like just smear your logic all over the place, which is bad.
I try to stick with plain React hooks when I can. For small-medium state complexity they're usually enough<p>For big stuff, especially deeply nested trees, MobX is still my favorite. It has some quirks but the core premise is such a simple and ergonomic mental model to work with, even for very complex state with intermediate derivations
Just use a global object and continuously run setState on the root component inside a requestAnimationFrame. Whenever you need to use or display something just reference or set the global object and you will be sure it's visually updated within the next rAF.
Jotai [1] is my go to, though I have never used it for anything too big.<p>[1] <a href="https://jotai.org/" rel="nofollow">https://jotai.org/</a>
Svelte. Simple and obvious global stores.<p>When working with Flutter I like provider. With React I use Redux Toolkit, but saying I like it is a stretch.
Keep it simple. Have global state where it needs to be global.<p>The easiest way to avoid problems with multithreaded writes to globals is to not have multithreaded writes to globals. Ensure all writes to said global only occur in one thread. One possibility is to use e.g. locks and semaphores to ensure only one thread writes <i>at a time</i>, but nothing can beat the amazing synchronity that is imperative programming. Try it out some time. Tell your friends.<p>The real secret here is that there are very few things that actually <i>need</i> to be globally writable. Most things that are global should be constant, so not a problem. For those which aren't, you probably have some kind of IPC message passing thing in your programming tool of choice. Use it to pass any state changes to global state to your main thread, which changes it. Be aware that race conditions may happen. If they cause you issues, make them not happen any more. Don't worry so much about life.<p>There will be problems with every approach. Pick one with few problems, and deal with them as they come. Multithreaded programming is inherently complex. No need to make it worse than it is.
hear me out on this:<p>hypermedia as the engine of application state<p><a href="https://htmx.org/essays/hateoas/" rel="nofollow">https://htmx.org/essays/hateoas/</a>