
Things I wish I knew about state management when I started writing React apps - thereyougo
https://medium.com/@veeralpatel/things-ive-learned-about-state-management-for-react-apps-174b8bde87fb
======
the_gastropod
I'm one of those "old dogs" who don't quite get the advantage of using React
in the majority of the cases it's used. This article didn't really help...

> What makes these frontends complex? State management. The frontend “knows” a
> lot of things, and these things interact with each other in non-trivial ways
> [...] Example: dark mode support. For example, say your app has a dark mode.
> All your rendered components must know what theme is on, so they can render
> the UI in the right color.

Back in my day.... you'd slap a class on the <body> tag, and you'd have all
you'd need for your CSS to style the rest of the page accordingly. How is
using Redux an improvement here?

None of the examples of "complex" front-ends would be at all difficult in an
old-school "just re-render the page" setup using something like pjax or
turbolinks. And in my experience (seeing web pages with > 1MB js files) it'd
be faster/more responsive for the end-user too.

~~~
jfengel
React and Redux are for apps. If you can do it with HTML/CSS, you absolutely
should.

React/Redux are a replacement for what people used to do with jquery or plain
JS. They're not for display; they're for complex interaction of the kind that
used to require a native user interface (Java Swing, Gtk, Win32, etc).
Javascript is a mess, and the DOM is a mess; React makes that slightly less
awful. (Redux is an extension to React to help manage global state; again,
it's compensating for just how bad Javascript is.)

Bonus: React encourages the use of JSX, a language that makes a lot of
behavior look as if you were writing it directly in HTML. You don't need React
to use JSX, and you don't need JSX to use React, but they do dovetail nicely.

You can write in plain JS/jquery if you want. Plenty of people do. React is a
framework to make that a bit easier; that's all.

~~~
the_gastropod
I actually write a good bit of React professionally. I'm familiar. I just have
yet to see a very compelling case. And the excuse is almost always this
nebulous "rich/complex interaction". And.... I just rarely see any good
examples of this. The _huge_ majority of apps (web or otherwise) are not video
games. They're forms that submit stuff to a server and get a response. There's
sometimes a dropdown here or there.... and that's it.

~~~
nepeckman
I see this sentiment on hacker news a lot, and I honestly dont get it. A list
of functionality I've implemented that requires (or is made easier by)
JavaScript: Client side validation, error messages, autocomplete, dynamically
picking/removing/auto filling fields based on user input, forms that need to
know user answers to previous forms, smart tables, update of data pushed from
server, sharing markup/functionality between pages, removing markup when no
longer needed, adding markup when relevant, etc.

Of course, all of the above functionality can (and has been) implemented in
jQuery, or vanilla js. But using a framework makes it easier to structure and
edit the project.

~~~
the_gastropod
> Client side validation

The server still needs to validate, no? I've never seen a form that really
benefitted from client-side validation. As long as required fields are clearly
marked, I don't really understand the value here.

> error messages

Hmm? What about them needs React?

> update of data pushed from server

You can poll very cheaply. And even Websockets are pretty simple. Check out
Phoenix LiveView or Rails Action Cable for decent examples of trivial
solutions to this.

> sharing markup/functionality between pages

Even Apache server-side includes let you do this. We're not talking about
hand-rolling plain HTML files in MS notepad (or even going wholly js-free).
We're talking about React being overkill in a lot of places.

~~~
johnmaguire2013
> I've never seen a form that really benefitted from client-side validation.
> As long as required fields are clearly marked, I don't really understand the
> value here.

Required fields are typically not the only type of validation required by a
form. I think a designer would see the value of client-side validation more
easily than a developer. It's not to ensure correctness - it's to give the
user quick and actionable feedback.

> You can poll very cheaply. And even Websockets are pretty simple. Check out
> Phoenix LiveView or Rails Action Cable for decent examples of trivial
> solutions to this.

React isn't helping you poll - it's helping you structure your application in
a way that ensures all components receive the updated data.

~~~
the_gastropod
> it's to give the user quick and actionable feedback.

Right.. But I think often times the difference is pretty overblown. Clicking
"save" and getting that feedback in ~100ms is not, in my estimation, worth the
massive extra overhead of using a front-end framework, duplicating your
validation requirements, etc. If you're google or facebook or youtube or are
otherwise printing money, go for it. But for the 99% of web apps out there, I
think this is a bad trade.

> React isn't helping you poll - it's helping you structure your application
> in a way that ensures all components receive the updated data

Right.. But so is just re-loading (most of) the page from the server. Again,
e.g., Phoenix Live View or Action Cable style.

~~~
ncallaway
> Right.. But I think often times the difference is pretty overblown. Clicking
> "save" and getting that feedback in ~100ms is not

Let's say the form has 5 fields, and I as the user make an error in the first
field.

Why do I have to finish filling out the entire form to hit "save", to discover
I made an error in the first field? That's not a difference of ~100ms, that's
a difference of several seconds (or tens of seconds for a medium-complexity
form).

~~~
flukus
>Why do I have to finish filling out the entire form to hit "save", to
discover I made an error in the first field?

Because more validation will usually happen on the server side anyway and
finding out when you hit save creates less interruptions to your flow. There's
no tabbing back to re-enter a field, there's no thinking it's fine only for
the server side validation to reject it and there's no nagging when I skip a
field to come back to it later, there's no UI jumping around when the error is
shown. Client side validation takes a stateless form and interrupts me with
it's stateful validation. At best it's an interruption, all too often there
are silly things like not letting you tab to the next field or warning you
that the second password you haven't yet entered doesn't match (and then later
telling you about other problems when the backend does the validation).

Not to mention it's easier, whether you agree or not with "developers are
expensive so performance doesn't matter" in a world where this is often said
I'd expect more server side only validation because client side validation is
duplicating the work.

I don't think client side validation is necessarily bad, but most
implementations get in my way more than the server side equivalent.

~~~
ncallaway
> all too often there are silly things like not letting you tab to the next
> field

Well, that's a criminal use of client-side validation, but it shouldn't
condemn all client-side validation.

> Not to mention it's easier, whether you agree or not with "developers are
> expensive so performance doesn't matter" in a world where this is often said
> I'd expect more server side only validation because client side validation
> is duplicating the work.

That's fair, but as others have noted if you're in a world where a polished
user-experience really makes a difference or is a competitive advantage I'd
argue that well executed client-side validation can get you to a UX-quality
bar that no amount of server-side validation can reach (edit to add: server-
side validation is still, of course, absolutely required).

Whether that's truly important for a given business or product can only be
argued on a case-by-case basis. I think it's definitely a colorable argument
that there's _some_ overuse of client-side validation relative to product
goals, but I think there are _definitely_ places where client-side validation
is hugely impactful.

Again, all of this assumes that the client-side validation is implemented at a
high quality bar. Of course _bad_ client-side validation is not useful.

------
brlewis
Point 1 in this article is totally misguided. "State management is how you
mitigate prop drilling" implies that when prop drilling is not a problem (i.e.
most of the time), that you don't need to think about state management. Even
if you're prop drilling, you need to make sure data is not stored/updated in
multiple places in your app in order to keep the UI consistent.

The one redeeming part of that section of this article is that it links to
another article that isn't as wrong. The linked article details when prop
drilling is and isn't a problem. And most of the problems it describes can be
reduced by using TypeScript. [https://kentcdodds.com/blog/prop-
drilling](https://kentcdodds.com/blog/prop-drilling)

~~~
veeralpatel979
Hey - author here. I did not mean to imply that state management is only
useful to mitigate the prop drilling problem. In fact, in #2, I give another
example where state management is useful.

~~~
brlewis
The first section reads as if it's explaining why state management is needed
at all, not as if it's giving one example of something state management is
good for.

I couldn't make sense of the second section either. It sounds like it's
recommending a global store as the solution to updating a single component.
The correct state management for a single component is what comes with React.

------
PaulDavisThe1st
So let me just check that I understand this correctly.

A whole bunch of problems that were "solved" (or at least, had fairly good
solutions) in the context of desktop GUI toolkits have resurfaced in the
context of application development confined to the web browser.

Almost none of the previous "solutions" are usable, because of the specifics
of the theoretically portable "browser platform" for which all this
development is taking place.

So instead, an entirely new set of frameworks are slowly being developed to
solve the same set of problems that desktop developers worked on 20+ years
ago, and are slowly converging on similar approaches?

Is that too cynical, or just about right?

~~~
cactus2093
Genuinely curious, as someone who wasn't building desktop apps 20 years ago,
what are the toolkits you're referring to?

When I google "cross-platform desktop frameworks", the entire first page of
results are all about the modern toolkits like Electron, Photon,
ReactNativeEverywhere, etc.

So it seems like your complaint is many years too late at this point. Maybe
there were solutions to this 20 years ago, but if I'm starting from scratch
today trying to build a cross-platform app, what I'm looking for are
frameworks that are mature, well documented with lots of tutorials on how to
do basic things, and have a large community around them for getting help on
e.g. stackoverflow. It doesn't really matter what has been around longer, if
the newcomers have surpassed it on these fronts.

~~~
rendall
How do these older frameworks (Qt, etc) approach state management?

~~~
PaulDavisThe1st
Well, first of all, the problem in its most basic sense doesn't even really
exist for many places where you would use "Qt, etc". You wouldn't be reacting
with a remote server or if you are you have a stateful connection with the
remote server. That's true whether the "remote server" is just a database
server or something more specific.

But going somewhat deeper (and based on reading all the defenses of "React,
etc" in the comments thus far), the fundamental difference is that if you were
using a desktop GUI toolkit, you would almost certainly assume that there's
essentially zero cost (or almost neglible cost) to the communication between
the data (model) and the GUI. This is (one of the things) that is so different
for web development, where everybody is struggling to optimize away roundtrips
back to the data (server), because it actually costs.

Put differently, whatever protocols might be implemented inside a desktop GUI
to talk to a not-in-memory data source, the protocols are almost certainly
designed for precisely that purpose. Whether its a vendor-supplied connection
to an SQL database, an application-specific serialization/deserialization
protocol, some IP-based message passing protocol ... whatever, it will all
have been designed for the express purpose that it is being used for (more or
less).

HTTP? Ahem. Granted, web app development has augmented HTTP in various ways
(most dramatically would probably be websockets/webrtc). But fundamentally,
the state management issue in a web app originates with the fundamentally
stateless communication protocol being used between the app and the data
sources/servers it is dependent on.

~~~
wruza
>if you were using a desktop GUI toolkit, you would almost certainly assume
that there's essentially zero cost (or almost neglible cost) to the
communication between the data (model) and the GUI

Which is true, because model is what you’re working with and binding to (along
with a controller). You can populate your models from a roundtrip data source,
if it is not local. How is that different from web apps?

I think this is the good old “ancients were less smart” stereotype. Client-
server and 3-tier apps didn’t begin with web. Heck, even lan
latency/throughput/cpuclock were comparable to what modern internet timings
impose.

~~~
PaulDavisThe1st
Some of what you've said here strikes me as true, as long as you limit the
domain to "applications" aka "database client-server front end foobars".

It's really not true for any desktops in the "creation" realms that I
mentioned. The data model for an image manipulation program or a spreadsheet
or a DAW or a document preparation system is fundamentally in memory, and
there's no roundtrip to anywhere to access it or to modify it.

~~~
wruza
I suspect I’m repeatedly misreading this subthread then. My point is that web
apps are still apps, no matter whether app data came from http or fs or sql.
It is unclear why good old methods of slapping data controls together wouldn’t
work and why is it so hard and esoteric to do fullstack today and learning
curves are so steep even for a simple crud++ area.

------
qwerty456127
> Think about the most complex frontends you’ve used. Frontends that made you
> wonder — “how did they create this”? What makes these frontends complex?
> State management. The frontend “knows” a lot of things, and these things
> interact with each other in non-trivial ways. So in my view, state
> management is the core problem when developing a UI. To build a non-trivial
> React application, you need to consider state management, in my view. For
> example, say your app has a dark mode. All your rendered components must
> know what theme is on, so they can render the UI in the right color.

This makes me wonder “how did we allow this to happen”? The beginning of this
article alone reflects the whole tragedy of modern programming. When I was a
child we would just use common controls and the operating system would paint
them whatever way configured in the control panel. Now we have to solve a
complex state management problem just to implement a dark mode. Application
programming was supposed to become simpler and easier, not this...

~~~
breytex
You got that wrong. Modern JavaScript / SPAs make it possible to implement
something like Outlook right within your browser. No (big) download, no
clicking through an installation wizard, no fragmentation of versions for a
tool, which forces you to be online anyway.

I don't get all the hate towards SPAs and JavaScript Frameworks here on HN.
Everyone is basically complaining about complexity for applications, which are
more than just a server-rendered form or message board (which is a way less
complex applications compared to outlook or slack, where "realtime
notification" is a requirement).

Application programming became easier by a lot, just the application
requirements grew at the same speed, resulting in that feeling of stagnation.

With something like zustand[1] or the react context api, its just ~10 lines of
code to store the dark-mode boolean somewhere central in the app and connect
it to all the components without prop drilling.

[1] [https://github.com/react-spring/zustand](https://github.com/react-
spring/zustand)

~~~
bcrosby95
I find lots of these "requirements" come from developers that are bored with
their job and need to spice things up.

~~~
veeralpatel979
Maybe! But also, as a user, I expect to do more and more in my browser.

I would find it strange, and probably switch to a competitor, if my preferred
airline for example made me install (and keep updated) a desktop app in order
to book a flight.

~~~
kungtotte
You do. Not everyone.

You know one thing I expect my browser to do that it has a hard time doing
these days? Efficiently and correctly displaying text documents.

It has a hard time doing this because so many web pages think they need to be
web apps and overthink things instead of leveraging the tools at their
disposal in the browser.

Yes, if you're building a new Outlook or Google Maps in the browser it ought
to be a web app.

If you're building the remaining 90% of use cases it should probably just be a
web page with boring old tech. Add JS for spice if you'd like.

------
vga805
What's the deal with the recommendation to use some library for managing
forms? I've been working with React almost since its initial release and I've
built some pretty complex forms... yet form libraries remain the one thing
I've never really seen a need for.

At the very least, using something like formik shouldn't be a necessity. There
should be some qualifier that it's only really needed for very complex forms.
Or am I missing something?

~~~
breytex
I felt exactly the same for many years, but when hooks where introduced, I
discovered _react-hook-form_ [1].

It just blew my mind how you can write complex forms with validations in just
a few lines of code.

Give it a try.

[1] [https://github.com/react-hook-form/react-hook-
form](https://github.com/react-hook-form/react-hook-form)

~~~
adamzapasnik
I've been looking for something like that, thanks for recommendation, gonna
use it on the next occasion.

------
pier25
> You can make API calls in your actions just like you normally would

Jesus don't do this. Mobx, Vuex, Redux, etc, are about managing application
state not about managing application logic.

I started making SPAs in 2015 and I also used actions for everything (API
calls, auth, etc). It was fine for small projects but then I got to work on a
medium sized project and those actions became huge and controlled everything
in my app. I usually consider myself a pragmatic person but that was
impractical for a number of reasons and also conceptually wrong.

When working in SPAs now I remove anything that is not state management from
MobX/Vuex/etc (I don't use Redux anymore). That logic belongs somewhere else.

The pattern I'm doing now is that I conceptually separate components from the
application logic. The store(s) feed data to the components but if the
components want to interact with the application they go through a mediator of
sorts (eg: changing a route, modifying state, authenticating, etc). This
mediator then interacts and coordinates with the different application
modules.

For example when authenticating many things have to happen in different
modules (API, store, router):

1) An API call has to be made to verify credentials and receive a token

2) This token has be stored somewhere eg: localStorage

3) Maybe we also need to make an API call to get user info, their roles, etc

4) Some state in the store has to be modified. Not only the user info, but the
app logic usually needs to know if a user is authenticated.

5) We need to tell the router to go to somewhere eg: /home

It makes no sense to do all that in an action. Store actions should be about
managing state, period.

~~~
hashamali
I think this is generally a side effect of people considering actions to be a
replacement for the Controller part of MVC. Meaning any sort of logic
(including legitimate state manipulation) is jammed into actions.

Personally, I don't see that as a huge problem. Better in an action than
sprinkled into components. As someone else mentioned, redux-thunk makes this
even easier (and one could argue, promotes this).

~~~
nohuhu
Another way of doing controller stuff is by actually using a Controller:
[https://github.com/riptano/statium#viewcontroller](https://github.com/riptano/statium#viewcontroller).
Example: [https://github.com/nohuhu/react-statium-realworld-example-
ap...](https://github.com/nohuhu/react-statium-realworld-example-
app/blob/master/src/components/Register.js#L117)

Logic flow doesn't have to be hard to do.

------
Waterluvian
I'm starting to lean towards holding ALL app state in a single store rather
than having component local state because every so often I get burned by not
seeing the future.

Example: okay I have a bunch of tabs that show different views. The state for
which tab is selected can live with the tab container. Months later I find
that I need other parts of the app to be able to switch to a different tab
when user actions happen.

At this stage all I put in local state are the most basic things like dropdown
open/closed state.

~~~
davnicwil
If you're looking to retrofit something like this in, just for a simple piece
of state like which tab is active, and don't want to refactor all your
existing local state management code, Context is a really powerful tool for
this.

I think of it like a dedicated state 'portal' \- should I need to use one
particular piece of local state in other components, I just write a quick
dedicated Context for that one piece of data (super quick and simple and
React-y using the new API) and simply set the context as well whenever I set
that piece of state.

Won't work for everything, is a little hacky in a way and you wouldn't do it
that way from scratch, but it's _such_ a quick and easy solution to this issue
compared to a major redesign of the global/local state.

~~~
williamdclt
Agreed, I use Context as a "store for UI stuff" and it always fitted
perfectly. Keep data in the global store (Redux or whatever), component-
specific state in the local state and inter-component state in Context.

And I wrap almost everything in hooks anyway, so the component doesn't care if
it's local, Context or Redux: it's just data and I'm free to move it in
different stores.

Tabs are typically the sort of thing that makes me think "context"
immediately. Also implemented nested collapsable sections with this, TikTok-
like feed where different components control the same UI component (sliding
panel), tables...

------
adamkl
To manage state in our React application, we have a "service layer", just like
you’d see in a server side application, only these are based on state machines
(reactive services based on RxJS observables works as well).

We also created associated custom hooks that allow developers to easily
"inject" a service into their React component (we use React's Context API for
our "DI container").

From there developers can read the service state to drive the look of the UI,
or send events to it to trigger behaviour that is encapsulated in the service
itself.

Our most used service is a UserSession service that manages OAuth based login
flow and session management.

The best part of this approach is that our service layer started in an Angular
based proof-of-concept before we lifted-and-shifted it all into React.

[1] [https://xstate.js.org/](https://xstate.js.org/)

~~~
onesmalldrop
I wouldn't call it the "best part." It sounds like you took the service
focused angular patterns you were using before and shoehorned them into a
React application.

How comfortable would you be allowing an outside dev to hack on your codebase
without a _long_ conversation beforehand explaining the idiosyncrasies?

~~~
adamkl
From my view point, we “shoe-horned” a React UI into a well-established
pattern for building an application.

I guess it depends on the vintage of the developer. I would argue that Redux
is an idiosyncratic technique for state management, and by breaking it apart
into separate services, you get better separation of concerns.

I should point out though, that our “service layer” follows the same event-
driven flow that you would see with Redux, but by breaking it up into state
machines we can be more explicit about the states of our application.

“Service layer” doesn’t have to be a dirty word. Redux is a stateful, reactive
service, and so are the xState machines we are using. Logically speaking, I
don’t see much of a difference.

As for the _long_ conversation you mention, in my experience, it’s actually
been a pretty short conversation followed by gratitude at not having to use
Redux. I really don’t meant that as a slight towards Redux, which is a very
elegant solution, but seriously, the people I’ve introduced to xState just
like it better.

------
andrewstuart
This post could more strongly emphasise something important to understand
about writing ReactJS applications - taking a declarative approach to the
overall application architecture.

Trying to write React applications in an imperative manner (the more
traditional approach to programming as opposed to declarative), twisted my
head in knots and made things harder and more complex than they needed to be.

What I mean by writing React applications in a declarative manner is:

1: you have a global state in your application

2: the global state includes an object with information about what state the
application is in, for example:

    
    
        globalState = {
         "DisplayingFormEditUserProfile": false,
         "DisplayingFormViewUserProfile": true,
         "DisplayingSideMenu": false,
         "DisplayingTopBanner": true,
         "DisplayingUserSignedInStatus": true,
         etc etc
        }
    
    

3: use React context to manage this state.

4: components decide to display themselves by querying the global state

It becomes easy then for your buttons and links to simply adjust the global
state to make things happen. Because React rerenders the application each time
the global state changes, you need do nothing explicit (imperative) to drive
the application - it all just happens automatically as a result of what
actions the user takes - actions that alter the global state.

React hooks and context make this approach very easy and clean to implement/

That's the way I do it anyway - an approach I find makes the entire
application easier to understand.

~~~
snowl
you just described redux or mobx (aka the article)

------
rhacker
I think the largest myth that exists in the react world is the need to have a
global state for everything. I've seen too many failures when teams go from
displaying "this one thing" to suddenly have the requirements to display two
or more of that at the same time. Redux global state for the user that is
logged in? that's OK, but do you really need Redux for that?

Our team uses hooks and context for everything, and a little bit of legacy
redux usage.

~~~
veeralpatel979
Hey! Author here.

You don't need to put the username of the logged in user into Redux, but if
multiple components across different pages need to access this data, you
should make it globally accessible.

You can choose Redux/MobX for this, or you can roll your own solution with
context and hooks.

I'm actually learning more about the context/hooks approach myself.

Kent C Dodd wrote a great article on this topic I'd recommend:

[https://kentcdodds.com/blog/application-state-management-
wit...](https://kentcdodds.com/blog/application-state-management-with-react/)

------
ChrisCinelli
For state management I would start with reading "Thinking in React":
[https://reactjs.org/docs/thinking-in-
react.html](https://reactjs.org/docs/thinking-in-react.html)

Step 3 is key. Step 4 is also important.

Then try to simplify the app as much as you can. A system has always 2 kind of
complexity: the intrinsic complexity and incidental complexity. "Smart
engineers" like to show off their intelligence. That usually end up making
their life harder by adding a lot of incidental complexity that eventually
lead to fragile architecture and frameworks that add more complexity than
necessary.

~~~
ChrisCinelli
I do not like Redux a lot. It leads to a lot of boilerplate code and a lot of
extra files. It also exposes transparently the state that lead by default to a
coupling between the "internal" data rappresentation and the rest of the UI
components making refactoring a nightmare.

Mobx at least leads to a more concise codebase.

GraphQL and Relay/Apollo/etc help a lot to reduce the business logic in the
front and code to written in general.

~~~
acemarke
As I've mentioned elsewhere in the thread:

\- Our new Redux Toolkit package ([https://redux-
toolkit.js.org](https://redux-toolkit.js.org)) simplifies most common Redux
use cases,

\- Our new Style Guide docs page recommends patterns that result in simpler
code, such as using the "ducks" pattern for single-file logic (
[https://redux.js.org/style-guide/style-guide#structure-
files...](https://redux.js.org/style-guide/style-guide#structure-files-as-
feature-folders-or-ducks) )

\- And we're working on a docs rewrite that will update the tutorials to show
simpler approaches as well

------
danellis
Why is state management such a talked-about issue with React? Other than
distributed state, which obviously comes with its own set of challenges,
managing state doesn't seem to be an issue with any other language, framework
or platform. But with React, it seems to be a major part of the learning
curve, with entire tutorials dedicated to it and numerous libraries to help
with it in some way.

~~~
acemarke
Because React, more so than the other frameworks, puts such a strong emphasis
on "the UI output is entirely based on your state", while at the same time
there are some limitations to tracking state in ways that are inherently tied
to your UI hierarchy.

~~~
danellis
> the UI output is entirely based on your state

How could anything else be true?

~~~
acemarke
If you look back at a typical 2011-ish jQuery app, the exact opposite is true.

You might have a modal visible in the page, but the only indication code-wise
that the modal existed was in the DOM itself, because there was a one-time
mutation of the DOM via `$("#my-modal").dialog()`. The only way any part of
the app could _know_ if that modal was being shown was to check on the actual
DOM itself, like `$("#my-modal").is(":visible")`. Then you start getting into
weird bugs because maybe some other script has mutated the portion of the DOM
you cared about, or you're having to write logic to handle if the DOM _was_ in
this state and now needs to be in _that_ state.

What we've learned over the last decade or so is that while that is fine for
adding small amounts of interactivity to the page, it's not a maintainable way
to build large-scale application codebases.

Instead, you want to have an actual `isModalVisible : true` boolean be the
real source of truth, and the UI should just be a reflection of that value.

I'm not saying that React invented this idea or that it's exclusive to React,
just that React's docs and community has generally put a stronger emphasis on
that specific mental approach to designing the app:

[https://reactjs.org/docs/thinking-in-
react.html#step-3-ident...](https://reactjs.org/docs/thinking-in-
react.html#step-3-identify-the-minimal-but-complete-representation-of-ui-
state)

------
the_optimist
See also: Reagent. State is a first-class construct in Clojure/script, and
forms associated with statefulness and state management are directly
available. From that perspective, none of the front-ends presented appear
complex.

[https://github.com/reagent-project/reagent](https://github.com/reagent-
project/reagent)

~~~
St_Alfonzo
For more complex state handling in SPAs (subscription, event handling) re-
frame is a really great framework based on reagent/cljs.

[https://github.com/day8/re-frame](https://github.com/day8/re-frame)

------
kerkeslager
> For example, say your app has a dark mode. All your rendered components must
> know what theme is on, so they can render the UI in the right color.

Wait, what? Hell no. This is literally the core use case for CSS classes. And
while there are cases where CSS classes can cause problems, this isn't one of
them. This is a case where CSS classes _shine_.

This is like an article on how to use fire to solve problems, and instead of
choosing an example like staying warm or cooking food, the author leads with
an example like disposing of tires by burning them in the rainforest. It's
just an unambiguously bad idea.

There were a bunch of places where I wasn't familiar with the tools he's using
and am curious, but I'm certainly suspicious of anything he suggests after the
"use global state to reinvent CSS classes via JS" suggestion.

~~~
austincheney
Yeah, I have a stylesheet for layout and then one for each color scheme.
Changing the scheme is literally changing the class attribute of the body tag.

Maintaining state isn’t that much harder.

------
rossmohax
I know nothing about state management on frontend, but please make supporting
"history back", "history forward" and "F5 reload" use cases easier. It seems
to be a hard problem to crack, given how often these simple actions are broken

~~~
baddox
It's really not a hard problem to crack. In most cases where history
navigation doesn't work it's due to nothing more than oversight. It'll
generally just be someone doing a JS route transition in an onclick instead of
just making a JS routing-aware link with an href.

There are some cases where history is a bit trickier to get right, like
infinite scrolling. Some apps have it working, although with varying levels of
success in my opinion. The forum software Discourse does a pretty good job:
[https://discuss.emberjs.com/t/is-the-six-week-release-
cycle-...](https://discuss.emberjs.com/t/is-the-six-week-release-cycle-too-
frequent/7526/62)

------
sytringy05
Is it just me or does the state management / prop-drilling thing sound just
like a bog standard dependency injection problem?

------
nubb
I’ve been learning React and have been avoiding Redux out of fear of
complexity. However, as my app grows more complex, the need for a global state
manager becomes more apparent. Time to start learning Redux today :)

~~~
karatestomp
1) Redux is pretty simple, but some of the terminology is obtuse for no good
reason and makes it harder to get a grip on than it should be. "Action" =
event, "Action Creator" = any function that emits an event, it's basically...
not even a real thing worth discussing with its own special term. There,
problem mostly solved.

2) TypeScript is the only sane way to use it. The bouncing between files and
"wait, what was the shape of my state here?" crap is intolerable without it. I
mean that's broadly true of all Javascript but it's very noticeable with
Redux. This is doubly true if you're working on a team.

3) I've had a lot of luck abstracting Redux behind a broader client library of
some sort. You can expose the redux store itself and let the using code
"compose" it as usual, but stick most of the "action creator" stuff behind the
wall of the library, minimizing and moving to a more suitable level of
abstraction the surface area the calling code is exposed to. This is
especially nice if you may use the code in some environments where you don't
want to or can't practically use React—you can still easily re-use the Redux
portions, which is wonderful. Also tends to leave you with state code that's
easier to test in isolation.

4) One of the big limitations of it is that you can't reference one part of
your state from another. You have to copy, because of how Redux automagically
detects changes to the state tree. This has been a lot more annoying and
limiting than I thought it would be at first—turns out I need/want to do that
more often than I thought I did, and the more complex the app the more I want
to do it—but you've either got to learn to live with it or have some kind of
external, supplemental state management alongside Redux.

~~~
kingdomcome50
Nailed it. Not only do I share the same sentiments, I have also had a very
similar experience with 3.

Specifically, I like to be able to interact/test with my application as I
build it in the console. I have had much success with wrapping my "Action
Creators" in a API of sorts and mounting it to the `window`. This saves me
from having to either create some sort of one-off component to "get at" some
piece of functionality or hand-rolling actions in redux dev tools.

~~~
karatestomp
I've done similar things, and yeah, it's great for making quick-n-dirty
utilities to poke around with your data & state handling code. You can even
throw ugly non-React GUIs on top, trivially, including in something like
Electron (if, say, your application needs access to functionality or modules
not available on the Web, as could be the case for certain Javascript
deployment targets like mobile, set-top boxes, desktop, server, and so on).

------
SlowRobotAhead
This is one area I have to give a huge tip of the hat to Flutter and Provider,
BLoC pattern using streams (and transform streams!) and RX generally.

It's been a lot easier to comprehend coming from C than the React options.

------
JoeOfTexas
Shameless plug, but I created a dumbed down version of redux.

[https://github.com/joetex/flatstore/](https://github.com/joetex/flatstore/)

Most of the difficulty with Redux is managing actions and reducers.

Out of the box, flatstore lets you get/set from anywhere, with component
"connect" function to trigger re-renders on data changes.

It's probably only suited for smaller projects, but now you can prototype at
the speed of light.

------
john-radio
Help me out here. So state management refers to frontend tools like Redux and
Vuex, and it sort of represents the "backend of the frontend" in that it
defines constructs and their behaviors for the frontend to manipulate. Is that
a correct understanding? If so then doesn't it result in some bad code
duplication between e.g. the Redux layer and the Django models?

~~~
chrisco255
Not sure what you mean by "bad code duplication"? If you have a need for a
rich front end application you're going to need to implement some state
management on the front end. The back end is responsible for running APIs,
managing services, interacting with the database, and performing validation on
API calls. A good REST API is typically stateless. But a front end can't be
stateless. Let's take Facebook for example. The front end needs to track which
conversations are open, which users in your friend list are "active" or "away"
and render the appropriate icon, threads of conversations need to be woven
together on various panes on the screen, visual feedback about whether a post
has already been "liked" by the current user needs to be provided, etc. It
needs to be able to receive real-time updates and post those to the UI in the
proper location. There's a ton of complexity there and you have to place that
state in memory on the client somewhere. Managing front end state effectively
is crucial for complex applications.

------
wruza
May I ask React guys what’s wrong with parallel controller tree and (virtual)
view tree which React tries to avoid (and, in my opinion, creates a bunch of
in-club issues on a way that didn’t exist outside of its paradigm)?

I’m talking about this desktop mvc adapted to hyperscript approach:

    
    
      class AppCR extends CR {
        ctor() {
          this.db = new RemoteDB
          this.sidebar = new SidebarCR
          this.content = new ContentCR(db)
          this.val = {a:42, b:3.14, c:this.db.fetchC()}
        }
        render() {
          let {h, val} = this
          return h.div.wrapper(null, [
            this.sidebar.render(),
            this.content.render(),
            h(AuxViewType1),
            h(AuxViewType2.model(this.val, "c")),
            h.div(val.b),
          ])
        }
      }
    
      class AuxViewType1 extends View {
        render() {
          let {h, cr} = this
          return h.span(cr.val.a)
        }
      }
    
      class AuxViewType2 extends View {
        render() {
          let {h, model} = this
          return h.model_input({model})
          // model == {object, key} (for "input")
        }
      }
    

Your controllers localize data, speak to the model in a non-ambigous way,
provide data for views directly (no props, think view.cr and view.model works
at any depth) and integrate other controllers by creating/destroying them
_explicitly_ and rendering when they are needed.

You also may have a global read-only (mostly) store of reference data, but
that’s more for caching large datasets, not for state sharing.

Btw, model_input could wait on a val.c promise and rerender appropriately
without your intervention (something React folks were to deliver last year,
supposedly with help from async setstate process, which was a requirement for
that (why?)).

All of this React thing honestly feels like Haskell sneaked into an enterprise
for the sake of “so cool we did it” giggles. Dan’s comments on this did not
help much when I read ‘em.

------
brlewis
Point 2 in this article says a global store is the solution to its example
problem. If there are any details of the example problem that make a global
store the best solution, those details are not given. Generally you store a
component's state in the component, and store shared state in a common
ancestor of the components that share it.

~~~
mfrye0
Yeah, he didn't do the best job of explaining why in that example.

Using a global store makes sense when your todo list evolves and the component
storing the data is no longer mounted / exists. Examples could be:

\- Full page individual todo edit \- Separate component / page that uses the
same data \- Some background logic that does X based on the todo data

------
rwieruch
With the release of React Hooks and the advent of GraphQL + its client-side
libraries, state management [0] became a blessing IMO. Whenever it's possible
I would opt-in using GraphQL for client-server communication. Then popular
libraries like Apollo Client help you with all the state management for remote
data and its caching. After this, all the remaining state management can be
done with React Hooks (useState, useReducer, useContext)[1]. Only if this gets
out of hands, opt-in Redux/MobX/...

\- [0] [https://www.robinwieruch.de/react-
state](https://www.robinwieruch.de/react-state)

\- [1] [https://www.robinwieruch.de/react-state-usereducer-
usestate-...](https://www.robinwieruch.de/react-state-usereducer-usestate-
usecontext)

------
thereyougo
OP comment on Reddit:

>[https://old.reddit.com/r/javascript/comments/f1jop9/6_things...](https://old.reddit.com/r/javascript/comments/f1jop9/6_things_i_wished_i_knew_about_state_management/fh6oi33/)

------
hi41
I am just a regular C/C++ developer. When I read OP's article, I was dismayed
by the number of tools or frameworks he refers to. I wish to become a web/app
developer. How do I climb such a steep curve? Can someone please suggest a
good online course.

~~~
tobyhinloopen
Just start with a plain React application, follow the react tutorials. Build
something simple.

Other tools and frameworks are all optional. I’m a frontend dev and I never
used many of the tools he mentioned.

------
bowlingx
I used redux before switching to Apollo and a query parameters / routing based
state management. In Web Applications especially, it makes sense to couple
global state to URLs. It makes the page and the current state shareable and
brings value (like tabs, filters, pagination etc.). I developed a library
based on zustand and immer for this case (called Geschichte). It’s open source
[https://github.com/BowlingX/geschichte](https://github.com/BowlingX/geschichte)

Most of the use cases I can solve with that, the rest is usually either forms
(covered by formik, final-form etc), async loading of data (Apollo) or local
state and animations.

------
deanclatworthy
Didn’t catch any mention of hooks in this article. My advice is only use redux
when two components need access to the same information within a few seconds
of whatever you are doing.

Otherwise I’d put all data fetching into hooks which can give any component
which uses it access to all kinds of information and the ability to
conditionally render.

I have found this pattern to be cleaner than using component lifecycle
methods. An example can be seen here:

[https://github.com/deanc/buyxiny.com/blob/master/site/src/co...](https://github.com/deanc/buyxiny.com/blob/master/site/src/components/ItemList.js)

------
soneca
Ok, only tangentially related. I would appreciate anyone more knowledgeable
than me in React chipping in: Why Redux is the norm for React state
management?

Follow-up specific question: In which cases is it better than react-easy-
state[0]?

I am using react-easy-state on my company and on my side-project web apps. For
me at least, it seems to add much less cognitive overhead than Redux. It is
simpler to understand, simpler to use, simpler to read and maintain.

Am I missing anything? Because react-easy-state seems very underrated in my
opinion.

[0] [https://github.com/RisingStack/react-easy-
state](https://github.com/RisingStack/react-easy-state)

~~~
acemarke
I'm a Redux maintainer. There's a bunch of reasons why Redux took off:

\- In 2014, a year after introducing React, Facebook announced the "Flux
Architecture" concept [0]. Since it was mostly just a pattern and not a
library, over the next year the community created dozens of competing Flux-
style libraries, which I've referred to as "The Flux Wars" [1].

\- Redux came out in the middle of 2015. Its design took inspiration from many
of the existing Flux libraries, but then added some Functional Programming
principles on top of that [2]. Many React devs concluded that Redux was the
better Flux implementation, and several of the other Flux library authors
promptly stopped working on their libs and began recommending Redux.

\- Redux was designed to work well with React from the beginning, including
the design of the React-Redux API [3]. Among other things, React-Redux made
use of what was then a little-known React feature called "context", which
enabled users to avoid prop-drilling values all the way down the component
tree. In addition, the initial sales pitch concepts of "time-travel debugging"
and "predictable state updates" appealed to many developers who had seen
problems with libraries like Angular and Backbone.

\- Along with all that, Dan Abramov had already picked up a bit of a
reputation in the React community from his work on things like React-DND and
some Flux-related blog posts.

Once Redux hit an initial critical mass, it became self-sustaining. People in
the community assumed that if you were going to use React, you _had_ to use
Redux. Tutorials were written that taught both of them together (along with
setting up Webpack and Babel from scratch). Now you've got bootcamps teaching
beginners React and Redux at the same time (which is unfortunate, because we
recommend that people should focus on learning React first, and only tackle
Redux once they're already comfortable with React).

Today, there's certainly plenty of other good options out there, with varying
tradeoffs. My own estimates are that around 50% of all React apps do use
Redux, and overall absolute usage is continuing to grow [4].

More recently, our new official Redux Toolkit package has been designed to
simplify many common Redux usage patterns, and is now our recommended approach
for writing Redux logic [5].

[0]
[https://facebook.github.io/flux/docs/overview/](https://facebook.github.io/flux/docs/overview/)

[1]
[https://blog.isquaredsoftware.com/presentations/workshops/re...](https://blog.isquaredsoftware.com/presentations/workshops/redux-
fundamentals/intro-history-goals-reducers.html#/15)

[2] [https://blog.isquaredsoftware.com/2017/05/idiomatic-redux-
ta...](https://blog.isquaredsoftware.com/2017/05/idiomatic-redux-tao-of-redux-
part-1/#redux-s-influences-and-goals)

[3] [https://blog.isquaredsoftware.com/2018/11/react-redux-
histor...](https://blog.isquaredsoftware.com/2018/11/react-redux-history-
implementation/)

[4] [https://blog.isquaredsoftware.com/2019/03/presentation-
state...](https://blog.isquaredsoftware.com/2019/03/presentation-state-of-
redux/)

[5] [https://redux-toolkit.js.org](https://redux-toolkit.js.org)

~~~
SlowRobotAhead
Can you comment on why people who like Redux on React don’t use it much when
moving over to Flutter?

I’ve heard “yea, you can use Redux, but don’t” a lot.

~~~
acemarke
Sorry, I have no experience with Flutter or knowledge of how Redux is being
used with it, other than having seen one or two random comments where the two
names appeared together.

~~~
SlowRobotAhead
Thanks anyhow. I think part of the difference is javascript doesn't have
streams, but Dart does. And that it's recommended to use the tools built in to
the lang, but there must be more to it.

------
ellius
Bounced around 2 projects in the last 12 months, one Angular and one React,
that are using the Flux pattern. It is a real bitch to unit test anything but
the individual pieces, which ends up being kind of meaningless.

~~~
lucasmullens
> unit test anything but the individual pieces

Isn't that the definition of a unit test?

~~~
ellius
Debatable but I get your point. The thing is that Flux is a pattern, and you
often want to test the full pattern to get a meaningful "unit" of
behavior/logic. There can be meaningful logic in the individual pieces, but
frequently they only make sense as a whole.

~~~
onesmalldrop
It's not debatable...

Unit tests are for testing individual components of your application (web or
otherwise)

e2e or integration tests are for testing your application
component/lib/api/whatever boundaries

~~~
nohuhu
How do you test individual components in isolation if they depend on the
global state store?

~~~
root_axis
That's a code smell. 99% of components in a project should rely on props.

~~~
nohuhu
How does that play with Redux Hooks for example? [https://react-
redux.js.org/next/api/hooks](https://react-redux.js.org/next/api/hooks)

If you are using hooks in your components, you need the global store instance.
To call this unit testing is too big a stretch for me.

------
reilly3000
I haven't seen much mention of Apollo here. It offers a 'full stack' state
management solution from server to client to offline cache. Each component can
be adopted independently, but they work really nicely together. The tradeoff
is that you're writing graphql, but it comes along with a lot of benefits,
like consolidating requests etc. On the server-side, graphql can be a thin
wrapper over rest apis. Defining good schemas can be a bit of a pain, but they
maintain a level of consistency throughout the system as it grows.

~~~
veeralpatel979
Hi - author here. Thanks for mentioning Apollo. I've actually abandoned
maintaining any data state in my global stores. I just use Apollo and provide
a refetchQueries to my useMutation call to update my UI after mutations.

[https://www.apollographql.com/docs/react/api/react-
hooks/](https://www.apollographql.com/docs/react/api/react-hooks/)

------
jkleiser
Great article! I have only done a few simple projects with React, except for
one where we used Redux. For me, Redux is too much clutter. I can recommend a
look at this article: [https://medium.com/@yiyisun/redux-vs-the-react-context-
api-v...](https://medium.com/@yiyisun/redux-vs-the-react-context-api-vs-
apprun-f324bee8cbbf) I've been working on an AppRun based hobby project for a
couple of months now, and I find state management there to be quite easy. No
clutter!

------
alfonmga
I'm in the process of building a B2B multi-tenant SaaS application and one of
the best decisions I made so far was to use Easy Peasy [0] to handle the state
of my React application logic. It has a very intuitive and powerful API. I
would recommend everyone to take it a look as it is not very known.

[0] [https://github.com/ctrlplusb/easy-
peasy](https://github.com/ctrlplusb/easy-peasy)

------
disease
> URL state: the route the user is on now. Read and update window.location;
> don’t create a second source of truth

I've seen so much back and forth on this issue during my time developing with
React. Intuitively, it seems like the URL should be treated the same way that
DOM elements are: as a source of actions that may or may not result in state
change - in addition to a reflection of state.

------
jeffadotio
I have abandoned all of the JavaScript state management libraries and now
prefer to simply write my own storage module using Meiosis[1] and a tiny
library for operating streams. This replaces tech debt and repetitious
boilerplate code with simple, meaningful and functional code.

[http://meiosis.js.org/](http://meiosis.js.org/)

------
nojvek
This post is overly complex in its suggestion of libraries. He does have a
good point of understanding different kinds of state and that state management
in front end is perhaps the hardest problem. If you think about it well
earlier, a lot of things become easier as you scale.

~~~
veeralpatel979
Hey - author here.

I agree that libraries for certain things, like MobX/Redux or Formik, may be
overkill.

What's more important, though, is that people choose an appropriate equivalent
to these libraries. Replace the library, but not the method of organizing
state.

For example, feel free to replace MobX/Redux in my post with your own global
state management solution. But I recommend replacing it with a global state
management solution, not something else.

------
mfrye0
For anyone not familiar with UI app design, you do not need to always default
to a Redux or Mobx. I've found a simple object / class with an event emitter
will suffice for many cases.

~~~
crtlaltdel
yeah i used this for a while [https://www.npmjs.com/package/tiny-state-
manager](https://www.npmjs.com/package/tiny-state-manager)

------
jaimex2
Been using alt.js for ages and continued to make use of it in React, never
really ran into the issues described.

Use it as a store or cache that alerts all your components of data changes,
works well enough.

~~~
veeralpatel979
Hey - author here. This is my first time hearing of alt.js. How does it
compare to more popular solutions like Redux and MobX?

------
reggieband
> but you do need to figure out how to store global state that can be accessed
> anywhere in your application.

Immediately I disagree and feel antagonistic towards this article.

Then the author provides an example of "prop drilling". Sounds an awful lot
like Inversion of Control [1]. I've been down this road before. Next comes a
Services pattern [2] (the world re-invents COM once again) and then comes
Dependency Injection [3]. What he calls "global state" others have called
"cross-cutting concerns" [4]. Pretty soon we'll be all aspect-oriented-
programming [5] up in here.

> What you need to do is store your theme setting in a Redux or MobX store, or
> in a plain JavaScript object, and pass it to all your components using
> Context.

Yup. The beginning of a services pattern by changing to inversion of control.
Once you realize you don't want all of your state on a single object you'll
have `context.getUser` and `context.getTheme` and then you'll think having
specific functions is a pain so you'll have `context.get(ContextType.User)`.
Then you'll have interfaces so you can easily unit test with mock services.

This is all good stuff. Keep going down that road.

1\.
[https://en.wikipedia.org/wiki/Inversion_of_control](https://en.wikipedia.org/wiki/Inversion_of_control)

2\.
[https://en.wikipedia.org/wiki/Service_layer_pattern](https://en.wikipedia.org/wiki/Service_layer_pattern)

3\.
[https://en.wikipedia.org/wiki/Dependency_injection](https://en.wikipedia.org/wiki/Dependency_injection)

4\. [https://en.wikipedia.org/wiki/Cross-
cutting_concern](https://en.wikipedia.org/wiki/Cross-cutting_concern)

5\. [https://en.wikipedia.org/wiki/Aspect-
oriented_software_devel...](https://en.wikipedia.org/wiki/Aspect-
oriented_software_development)

------
jrochkind1
Is MobX catching on?

~~~
purplerabbit
No :( unfortunately it's more of a library than a framework, and there's no
broad consensus on how it should be used (although there are certainly some
opinions floating about on that front)

------
k__
I don't even use any of these state libraries.

All logic in the page/screen components and the prop-drill them down to where
they are displayed.

~~~
veeralpatel979
Author here.

I see the appeal of the simplicity of this approach, and this is how I handled
state in my application before I knew what state management was.

But how do you deal with the problem of many of the components in your tree
needing to know what theme is set?

~~~
k__
I used CSS frameworks for theming.

~~~
veeralpatel979
Ok; ignore that specific example -- if you needed to share a piece of state
among many components in different places in your component tree, how would
you do it?

~~~
k__
I have 3 tiers of components.

Root - Page/Screen - UI Elements

The Root takes care of authorization and navigation logic, to switch between
pages.

A Page has all the logic needed for one page it holds all the state and passes
it down via props.

A UI Element displays the state it got via props and sends up its events via
handler function (it also gets them via props)

In 90% if cases this was enough.

Sometimes, I needed to pass some state from the Page up to the Root and from
there down to another Page after navigation, but that was it.

~~~
veeralpatel979
Got it. If you don't have any data that's shared between pages, I can see how
this works.

------
brlewis
In other comments I've pointed out specific major flaws in this article, but
for whatever reason it continues to be upvoted and has risen to number 6.

To be clear, this article is not useful. If you are trying to learn about
state management in React, do not read it. Read this one:
[https://kentcdodds.com/blog/application-state-management-
wit...](https://kentcdodds.com/blog/application-state-management-with-react)

