5 ms·
The purpose is reactivity: when X state changes, Y needs to update. How do we know which Y's care about which Xes? How do we initialize and clean up those assoc
by brundolf 5y ago
The purpose is reactivity: when X state changes, Y needs to update. How do we know which Y's care about which Xes? How do we initialize and clean up those associations as Xes and Y's get created and destroyed? How do we make sure X can't be mutated without triggering Y to update and stay in sync?
This is necessary on the web because it doesn't operate in immediate-mode. React, despite its name, doesn't actually solve the reactivity problem (well, setState and hooks kind of do, but they're pretty basic). The big deal with "state management libraries" like Redux and MobX is that they give you an enshrined container of state that knows how to publish its changes to the things that care about it, in a way that's more performant and ergonomic than the naive approach. That comes with different caveats and constraints depending on the library you choose.
You mentioned events, which can be part of a solution (just like regular callbacks can), but they don't actually solve the hard part of the problem.
- andrewmcwatters 5y agoThis hasn’t been a new concept for decades, though. What you’re describing is why we have event listeners. You dispatch events and only relevant listeners get those events. You don’t need a library for it. The “hard part” of the problem is that React doesn’t care about using simple solutions, because it has its own lifecycle you have to use. So inevitably any software that wants to interact with React would have to trigger React to respond to those events. This architectural decision leads to engineering solutions that make state management seem like a complicated thing, but the “reactivity” issue you’re describing has nothing to do with state management. It has everything to do with managing React to react to state changes. That’s not state management. That’s framework management.
- brundolf 5y agoYou don't really have to do anything special with React's lifecycle in order to publish changes... you just call forceUpdate on a component to trigger itself and its children to re-render. The trick is avoiding rendering the parts of that tree which won't actually change. Redux solves this through immutability which allows for reference comparison ("if this component's props didn't change then the object will === the previous one, and we can skip it"). MobX does it by automatically wiring highly granular pub/sub relations between individual variables and the components that reference them. Additionally, events aren't sufficient on their own because you need the state to actually be stored somewhere, for next time. Events don't hold state, they only pass a transient signal. And if you're manually both a) publishing an event and b) updating the corresponding state, you risk missing a case and having those two get out of sync (not to mention you'll be writing a whole lot of boilerplate logic). It'll also be really hard to change multiple pieces of state at once without having things temporarily disagree. I've worked on a project where this is basically what was done, and it was a nightmare of inconsistent intermediary states and race-conditions. To put it differently: "state X changed" is a special case of "X happened" that needs quite a few special considerations in practice, and that's why state management abstractions are built atop the more general idea
- andrewmcwatters 5y agoI appreciate the granular details of what you're saying, but with every sentence, I just think to myself, yeah that's React's problem that it's offloading to others.
- brundolf 5y agoMaybe! But that would mean going all-in on the "React is a framework, not a library" thing. Right now they're straddling the line where they can still argue that they're maybe kind of just a library, even if most people don't really buy it at this point
- midrus 5y agoI agree with all the overengineered stuff argument, but this is not as easy as you describe except for the simplest of the use cases. For example, you might have on screen a component (something inside a modal for example) that might need some data (a newly created record maybe) which is some information that has been dispatched in the past, so either you have to foresee and pre registered every single listener on beforehand or you have to keep track of all the events or the data that was emitted with them. At that point you've invented a new state management solution.