4 ms·
I think redux got 50% right and 50% wrong. 1. good: having a sideeffect-free, serializable application state. That concept can also be used in mobile apps for
by cel1ne 10y ago
I think redux got 50% right and 50% wrong.
1. good: having a sideeffect-free, serializable application state. That concept can also be used in mobile apps for easy pause/resume.
2. good: being able to render that state from one parent, because you don't need to manage two separate statemachines (the UI and the business logic) anymore.
3. bad: shoe-horning all state-transition into functions/reducers. Fp is awesome, but sometimes imperative constructs are more appropriate, especially in a mostly imperative language. Use fp where it feels natural, not everywhere.
4. bad: shoe-horning everything into immutable data-structures.
Seriously, when did
newName => {
this.name = newName
}
become
(state, newName) => {
return state.set("name", newName)
}
?
Just change the state. If you want to prevent errors, freeze and seal your state. If you want time-travelling debugging, copy it via serialization. No need to slow down production code by copying and throwing away data all the time.
5. bad: using Immutable.js, thereby slowing your code down by two or three orders of magnitude. And I guess losing many GC and JIT optimizations by throwing out different types of objects and pressing everything into the generic map-structures, that immutable.js uses internally)
I wrote multiple sites/apps using immutable and redux, but i'm back to pure react and lodash. Code is more concise, simpler and way faster, even though componentDidUpdate has to use lodash's _.isEqual instead of a simple comparison.
- talldan 10y agoUnless something has changed very recently, you don't have to use Immutable.js and redux together. Redux advises against mutating your state, but doesn't prescribe a way to do that.
- cel1ne 10y agoTrue, I did applications with redux and without immutable too, even wrote my own syntax magic for that: https://www.npmjs.com/package/babel-plugin-check-data-access https://www.npmjs.com/package/babel-plugin-check-data-access What redux misses as well are derived/computed properties, I think mobX has them: https://mobxjs.github.io/mobx/ https://mobxjs.github.io/mobx/
- acemarke 10y agoThe standard approach is to store the minimal amount of data directly in the state, and derive data as needed externally to the store. This is usually done with "selector functions". See http://redux.js.org/docs/recipes/ComputingDerivedData.html http://redux.js.org/docs/recipes/ComputingDerivedData.html , https://medium.com/@adamrackis/querying-a-redux-store-37db8c7f3b0f https://medium.com/@adamrackis/querying-a-redux-store-37db8c... , and http://redux.js.org/docs/faq/CodeStructure.html#structure-file-structure http://redux.js.org/docs/faq/CodeStructure.html#structure-fi... for more information.
- danabramov 10y agoUm, no, you don't need to use Immutable with Redux. And regarding syntax, with object rest/spread (stage 3): (state, newName) => ({ ...state, name: newName }) It's not that verbose.
- cageface 10y agoMy main hesitation with Redux is how awkward it is to insert async calls in the chain of events. Things like redux-thunk and redux-saga are impressive hacks but feel like a lot of gymnastics to do something that pretty much every React app needs to do.
- cel1ne 10y agoI dislike redux-thunk, because it breaks serialisability. I don't know redux-saga, but this is my way of doing it: Create a data-structure like "running requests" in your state and put a serializable object in, could be complex or just a string "GET_USER_DATA". Then write a simple "NetworkManager". React reconciles the UI to match the state, the NetworkManager does the same for your "running requests": make the actual running requests match those in the state. In some projects I even (ab)used React to do that: add a component that renders a <div/> and manage the XHR in componentDidUpdate etc. <Network> <Get url="http://..."/ onLoad={() => state.GETsuccess(...)}> </Network> This way everything can be paused and is easy to reason about. You get cancellation and reuse of requests for free by using keys.
- ng12 10y agoYou don't need to use Immutable.js (I never do) but making your state immutable/functional is what makes the magic work. You don't have to worry about observing data or manually handling data updates -- everything just works. Compare this to MobX where there's an explicit pubsub model. In my opinion that works best for small apps, but falls apart in large ones (where Redux shines).
- Chris_Newton 10y ago2. good: being able to render that state from one parent, because you don't need to manage two separate statemachines (the UI and the business logic) anymore. This is one of the areas I found to be most disappointing in practice about using a data store built with an immutable state tree and then using self-contained transactions to update it, which is similar to the Redux+Immutable model. One of my current projects is a somewhat large web application. It has relatively complicated state to maintain for a web app, with very heterogeneous data and lots of relationships and constraints to enforce between data points. In the early days, using React for rendering was quite convenient, and using Immutable then made writing shouldComponentUpdate quick and reliable, which was necessary almost immediately to achieve acceptable performance with React. Essentially, you’re using references within the immutable data as a proxy for a “dirty” flag on each part of your state. However, it wasn’t long before the presentation code started to depend on derived state that was expensive to recompute: temporary tables, automatic diagram layouts, etc. This is where I find the immutable data structures really lose out compared to some sort of lazy observer architecture, because you are back to having a synchronisation problem between your derived view state and your underlying data model. You can set up your derived view state as immutable values as well, and thus keep the reasonably simple shouldComponentUpdate mechanics, but you still need to either push changes from the underlying data model or pull them from the view. In the former case, you’ve effectively given up the declarative rendering that makes React more attractive than actively updating the DOM in the first place. In the latter case, you’ve created cache invalidation problems that undermine the benefits of having a cleanly updated, immutability-based data store in the first place. There are several other advantages that have proved to be useful with this particular combination of tools, but they do come with some nasty performance and scalability implications, and in particular, they don’t generalise and compose cleanly in the way that a good observer-based design would. Worse, I suspect the difficulty of managing derived view state efficiently is inherent to this sort of architecture, because it seems almost inevitable in any system with data complicated enough that using a separate data store and declarative view rendering is worth the performance overheads in the first place.