|
|
|
|
|
by acemarke
2151 days ago
|
|
Side note: I just published a brand-new "Redux Essentials" core docs tutorial. It teaches beginners "how to use Redux, the right way", using our latest recommended tools and practices, including Redux Toolkit for writing your Redux code, the React-Redux hooks API for interacting with Redux in your components, and use of single-file "slices" for a given feature's Redux logic. I'd encourage folks to check it out: https://redux.js.org/tutorials/essentials/part-1-overview-co... My next step will be to rewrite the existing "bottom-up" tutorial sequence to simplify explanations, remove outdated references, improve the explanation flow, and add more running examples. |
|
I recently (2 months back) moved a medium sized project (~240 branch reducers, ~600 actions) away from redux-toolkit.
My primary complaint is that the recommended setup doesn't work well with changing requirements where we often have to move away from branch-local state handling to something that needs access to wider state.
We started out with a number of slices and our reducer logic was local to these slices and used only the state within that slice. However as our application evolved, for processing a number of these actions (which were previously slice-local) we needed access to state from other branches. So now we had a couple of options:
A. Dispatch thunks instead of actions: This gets ugly real fast because now your action handling logic is split across thunks & reducers, and is hard to follow. This also needs refactoring across every dispatch site.
B. Use something like redux sagas to intercept actions: We found this to be "too" flexible and felt that we were better-off without the entire machinery of spawning sagas on the fly. We wanted it to be easy to reason about what happens when an action is dispatched looking at the code without having to debug what all sagas could be running at that particular point of time.
C. Move the action handling higher up: requires extensively refactoring the reducers.
The solution we settled on was redux-loop [1]: A port of elm's effect system to redux. This was neat because we could easily convert the reducer to return loops instead of states, and thereby easily get access to full state and dispatch while retaining the ability to follow through the complete action handling flow from a single starting point that didn't change.
TypeScript support in redux-toolkit is also kind'a bolted on and users are recommended different approaches when they care about type-safety. It proved to be a pain to communicate junior devs multiple times that you should use leave the reducers as empty object and instead use "extraReducers" with builder API.
We found using immer[2] (for managing immutable state) and unionize[3] (for handling discriminated union of action types) directly to be a much better solution than redux-toolkit's abstractions.
[1]: https://github.com/redux-loop/redux-loop
[2]: https://github.com/immerjs/immer
[3]: https://www.npmjs.com/package/unionize