Following my article on an intuitive, boilerplate-free global state solution for React, I decided to put real data behind the concept. I started with a bare-bones example of a React application that harnesses Redux for global state management, and I converted it to ReactN. During this process, I measured objective changes in memory allocation and bundle size. A thorough analysis and source code is provided on GitHub, but I will summarize here, as well as walk through how easy a conversion is and how much simpler the refactored code becomes.
The application is a showcase of global state features. On mount, the application fetches a page and stores the response in the global state. On render, a button displays a number from the global state. When the button is pressed, the number increments.
This isn’t breath-taking functionality. This is a demonstration of the three most important aspects of global state: the ability to read from it, the ability to write to it, and the ability to manage it asynchronously.
There are four parts to establishing a global state in React, and we will walk through each of them: the dependencies, initializing the global state, connecting the components to the state, and reading from and writing to the global state.
We need three packages to establish our Redux application:
redux, which contains the logic to create and interact with the global state;
react-redux, which contains React logic and higher-order components for integrating the global state with a React application; and
redux-thunk, a Redux middleware for processing asynchronous state modifications.
To initialize the global state, we use the
createStore function from the
redux package. To it, we pass the desired reducers and middleware.
The end result looks like this:
createStore function is quite the enigma, but I won’t spend this article discussing common developer complaints about Redux’s learning curve!
In order to connect the components to the state, we must wrap the application in a global state context provider, then wrap each connected component in a higher-order-component that behaves as a global state context consumer.
The end result looks like this:
That’s a lot of code just to use global state. Despite the
react-redux package being geared towards integrating Redux with React, I personally do not feel the above has a React-first approach in mind. But I won’t spend this article discussing common developer complaints about Redux’s boilerplate!
While this step includes the mysterious actions
incrementX, I included them in the next section, as they are directly related to writing to the global state.
With all of that boilerplate out of the way, we can finally use the global state! We access and modify the state through the connected component’s props.
The end result looks like this:
Actions aside, the component itself is very easy to read!
Now that we’ve seen the familiar Redux implementation, let’s see how we can decrease the complexity above and turn it into a more readable, more intuitive React application.
reactn package. There is no asynchronous middleware. ReactN supports Promises out-of-the-box. You can remove the three aforementioned Redux dependencies and sigh in relief as your application drops by 213 dependency files and has a 13% smaller production bundle size when it uses ReactN instead.
The first of the cumbersome boilerplate, time to initialize the store and establish the reducers. Reducers and actions are optional in ReactN. I only include them here for a fair comparison, as we are using them in Redux. If you find reducers to be too much boilerplate, you are more than welcome to abstain from using them. A reducer-free alternative is provided later.
setGlobal to literally just set the global state. Great for initializing.
addReducer to add a reducer. Note that ReactN does not use actions. We call the reducer directly!
We’ve reduced the boilerplate from 640 bytes to 330 while including actions! More on that later — for this project, I wouldn’t create a
fetchData reducer at all. I only include it here for symmetry with the Redux application.
ReactN does not use higher-order components. To connect your components to the global state, you add one byte to your file.
I added an
n to the end of the package name, changing
reactn. That was it. Your
PureComponents now have access to the global state.
That was 728 less bytes of boilerplate! One less app-wide HOC and one less HOC per component.
How do we use the global state if we didn’t tell it what props we want on our component? With React in mind, ReactN treats the global state as a member variable — exactly as you are used to using with local state’s
The component looks exactly the same — except to access the global state, you use the
this.global member variable instead of props. No higher-order component required!
That’s it! The component is done. It’s fully functional.
I mentioned how I would handle the fetch data action differently with ReactN, so I will elaborate here. ReactN is not limited to actions and reducers, like Redux. ReactN’s global state member variable is meant to behave exactly like React’s innate local state member variable, and that includes an analogous
this.setGlobal method that behaves like
fetchData is being called across multiple components, it doesn’t afford us much to name it as a reducer, so I would simply call
index.html, parse the text, create the state object, and set it.
I wouldn’t be opposed to the
incrementX reducer simply being a method on the component that calls
setGlobal either, since it isn’t being shared across components either.
I wanted to show the two applications, side-by-side, in their completed state, since the above really only covers snippets. The code below would be better served if it were split into multiple files, but the real issue is reading, writing, comprehending, and maintaining this code. This applies not only to you, the reader, but your team, which is often comprised of junior developers.
Whether you believe one method is easier to read than another, one thing here is objective. The above application in a production build is 531,736 bytes using ReactN. It’s Redux counterpart is 611,990 bytes — a 15% increase.
The difference likely drops with scope, as a project re-uses more actions, and contains significantly more logic unrelated to global state. However, with an increase in scope, you see an even greater reduction in boilerplate!
If you want to contribute to this project, it is open-source on GitHub, and I would be absolutely ecstatic for more community feedback. If you want to play around with this project, simply
npm install reactn --save or
yarn add reactn.
If you liked this article, feel free to give it a clap or two. It’s quick, it’s easy, and it’s free! If you have any questions or relevant great advice, please leave them in the comments below.