Closed joncameron closed 1 month ago
There are multiple state management solutions for React such as; Redux, Jotai, MobX, Recoil, etc. focusing on different areas of expertise and for different scales of applications. And from what I read in blogs, forums, and some documentation it seems Zustand and Recoil are the ones that provide better performance optimization when it comes to state management. And out of those 2, Recoil is a fairly new library with a steeper learning curve, suitable for larger applications which require advance state management.
The goal of the investigation was to evaluate whether we need to bring in a new library for state management or whether we could keep using the current solution with some modifications.
So, the comparison was made between Zustand and Context API (existing solution) with custom hooks (new implementation).
Using the existing React Context for state management with additional custom hooks. Custom hooks allow us to abstract reusable logic while the Context API provides a way to share state.
React.useEffect
), middleware, or persistent state (such as the custom hook for localStorage), which are provided out of the box in Zustand.A state management library that is minimal, highly performant, scalable, and easy to use. It provides a centralized way to manage state with less boilerplate and more advanced features compared to the Context API with custom hooks.
useOptimistic
and useTransition
hooks in React 19?) and doing other improvements, an external library could bloat the application in the future as things that Zustand (or any other library) offers now could be included natively in future? This is not a concern but something to think about if we decide to go with an external library.Zustand | React Context API with custom hooks | |
---|---|---|
Initial setup | Requires more effort, as we need to strip the existing state management system and setup a new library. Setting up Zustand should be easy as it has minimal boilerplate. Requires time and effort learn a new library. | Context API is already setup, but needs effort to identify code which could be broken into custom hooks and setting them up as needed |
Performance | Handled automatically by the library | Performance can still be degraded with unnecessary re-renders, as the application grows. These need to be handled manually |
Features | Provides async actions, support for middleware, and persistence out of the box | Highly customizable, but needs effort to implement and maintain these features. May be effort on this work would be reduced with changes in React 19? |
Scalability | Scales gracefully, and doesn't require extra work to make this work | Could be harder to maintain custom hooks and splitting contexts as the application grows, and the code can get complex as things grow |
Code quality and maintenance | Code would be cleaner, readable, and easier to understand for a new developer as there's minimal customization. But, this adds one more additional dependency to manage. | Code would be more complex than implementing Zustand as we add custom hooks and split contexts. But at the same time this option gives us the flexibility, as well as transparency (no magic!) in state management, and also the ability to re-use most of the state management code between components using custom hooks. And this doesn't require us to manage and maintain an external dependency as all of this is native. |
[!NOTE]
There is a possibility that none of this might fix the issue we were facing with collapsing/expanding sections inStructuredNavigation
component because of the nested architecture of that component. I suggest that, we explore whether there's a better way for us to populateStructuredNavigation
without the nested architecture and I can explore this as a part of this ticket. And if it's a possible solution and requires more effort, I think we can create a new ticket to continue that work.
One of the questions we needed answered with this investigation is to whether we can solve the structure re-rendering issue with fixing state management. So, I did a little bit of deep dive into the performance enhancement solutions I came across related to context API. I read more on custom hooks, and from what I understood it can be used to solve the structure re-rendering issue we had with state management. But I wasn't sure whether this will work with the nested architecture of the component. So, to explore this, I worked on a PoC. And it seems like it could be a solution for us if decide to keep working with context API state management.
We like the idea of staying the course with React and utilizing new functionality as it is added, rather than pivoting to a new library and potentially having to return in the future if the library is no longer supported or doesn't support new functionality. So stick with Context API and custom hooks. Pull out and encapsulate custom hook functionality that is reusable across components.
Ramp is using React 17. We need to update that to at least 18.3 before working on restructuring state management. React 18 has some new hooks to help with state loading and UI.
Create one more big ticket to identify code that needs to be built into custom hooks and do that work.
Description
What's the current state of the field in state management for React? Investigate and determine which we want to use moving forward as parts of Ramp are refactored. Multiple re-renders are a current paint point in Ramp.
There are multiple options for state management to explore.
Done Looks Like