Let's check how state management implemented with the RxJs library works in React. We'll implement a simple state manager using reactive patterns.
In React world, changes on UI are caused by state changing inside your components. To simplify, we can say that state is equal to UI.
Everything looks very easy if you have simple features. In more advanced ones or in a bigger application, state management can cause headaches. If you implement it in a wrong way, it can lead to huge problems with maintenance later.
Let's check how we can achieve nice and clean state management with rxjs and ContextAPI.
Yup, I know we have redux/FLUX and other stuff 👽.
1. State/logic outside component
Firstly, you need to move state management logic outside of React ecosystem. I know it may sound strange but trust me. With this approach you will have:
- Independent testing
- Option to easily migrate to other technology
- Easy to replace the logic
Multi-layered architecture is an investment. Of course, initially, it takes more time to implement something but later it saves a lot of your time if it's not too complicated.
Right now, we have the first layer which is responsible for the creation of store objects with public API. This API allows us to change the state and notify all subscribers.
2. Usage in React component
In React we need to use two hooks to connect our module with the functional component. With useMemo() we create only one instance of store object per component's life cycle. With useEffect() we update the state based on the signals from our module store and this triggers rerender.
This approach gives us the full power of rxjs. Right now, we can use the operator to handle side effects and other complicated logic.
3. Sharing state without ContextAPI
You can share created store inside components via simple imports statements between files. This gives you the same behavior as with redux without tons of boilerplate. As in redux you will need to reset the state if needed.
4. Usage with ContextAPI
This approach gives you full encapsulation and connection with React ecosystem. Right now, there is no need to reset the state. You determine in components where dedicated store API can be exposed in the component tree.
As you probably noticed we're exposing a dedicated hook to hide Context details.
Now, you have two options. You can implement state management with or without ContextAPI. It depends on your needs.
5. Let's create a consistent API
Of course, we can manually write this code for every feature, but it's a bit frustrating and time consuming. In addition, we can make some mistakes or provide different APIs. To avoid this problem we need abstraction.
Firstly, lets create createStore() function which allows us to create store object.
Next, we need a hook which reduces boilerplate and connects us to React ecosystem.
Lastly, a function that creates a full feature and adds ContextAPI support. This function will return the wrapper component and hook to consume provided API in the component tree.
Let's construct ContextAPI provider and hook for reading state/performing actions.
Right now you can use it in an easy way inside the component.
I hope you enjoyed this article. Now you are able to use rxjs in your projects. From my point of view, it works really well. It's lightweight and scalable, and you can customize it for your needs.
Remember, the solution which you should use depends on the project's specification.
Feel free to contact me if you have any questions/proposals. Have a nice day and good health!