React is unopinionated and may be that is a problem. React component has a state. The state within the component get a bit messy for any medium-sized application. State management libraries like Flux, Redux or Mobx are available to manage state. The Flux pattern enables uni-directional data flow in a React application. The article explains the various patterns available to manage state and control data flow. Choosing among the available alternatives earlier in a project helps to keep the code clean.
#1: Encapsulation vs Uni-directional flows
React components are reusable. The greatest advantage of React is to have the layout, style and behaviour encapsulated in a single component.
Consider a simple contact form with name and email. The contact form will have validations. Do we do all the validations within the component? If we do the validations within the component, we will be using the React state (setState).
The other alternative is to use our state management library to do the validations. In redux, we have redux-form which does such validations. In this case, we are moving away from encapsulation, and taking a puristic approach. In the pure redux / flux approach, state is managed by Redux and is passed down to component via props. In this approach, all components are functional or stateless.
However, a pure Redux approach has its own problem. Take this scenario: On selecting a checkbox, a textbox pops up. Using React State, this is a simple code to show / hide a React element. This behaviour is very much specific to the component. It makes sense to React State (setState). But, if you have made up your mind to do pure Redux, selecting a checkbox should dispatch a Redux action. And the new state should flow down via props.
Questions to answer for your project:
- When does it make sense to use setState? (encapsulation)
- When does it make sense to use Redux state? (uni-directional data flow)
#2: Single store (Redux) or Multiple stores (Mobx)
I have been using Redux and Mobx in my projects. Both do their job of state management in their own ways. Redux has a single store whereas Mobx (and Flux) have multiple stores.
Though Redux has a single store, it has multiple reducers each managing its own state. That might appear to solve the problem of partitioning state. But the problem is not solved till everyone agrees to it.
Apart from maintaining uni-directional data flows, state management libraries like Redux and Mobx serve a very useful purpose. They allow a group of components to share state. In the case of Mobx, the state abstracted to a store is readily available to a group of components that observe it. In the case of Redux, the entire store is available to all components depending on how you use it.
The choice of partitioning state into multiple stores or reducer is very important. Consider a grid that is built for displaying tabular data. The grid might have several sub-components all sharing the same grid state. The grid state can be abstracted into a common store in Mobx or a reducer in Redux.
Question for your project:
- How do you plan to partition state?
#3: Sharing state between components
Redux is opinionated but slightly unopinionated when it comes to how the store is used. The
react-redux has a Provider and Connector React component. There is only one Provider component and there can be multiple connector components. The connectors inject state via props to the component.
With React-Redux, there are two patterns on how to connect a component to the store.
- Have as many connector components. (Store holds the state)
- Have only connector components for the components specified in the route. (Container component holds the state)
The official Redux documentation suggests the second approach. With the second approach, only container components have props injected via redux connectors. For other components, the state is passed explicitly via props. This approach makes the code easy to maintain.
However, writing code this way usually bloats the props in the container components. Too many props are injected in the container component. The data flow via props though explicit can be hard to write. Many developers for want of time have resorted to connecting a lot of components to the store.
Usually, there are some reusable components which need to be used across multiple pages in the application. Such components are usually part of layout. I have also used “Contact Us” component in multiple pages, sort of call-to-action component. These components can be self-contained and should connect to the store directly rather than relying on parent components to supply state.
Questions for your project:
- Do you want to adopt the suggested approach by Redux team to connect top level components to the store?
- Do you want to share the state with components by using multiple connectors?