How does Redux work for React apps?

Redux is a state management library for JavaScript apps. The core Redux library implements the flux pattern. In this post, I won’t be writing about the Redux library but the react-redux library which has the plumbing code to integrate Redux into React apps. When we use react-redux library, the plumbing code that makes it work is hidden from us. Without knowing how it works, we may not know how to optimize our apps.

Redux store

We will use create-react-app or CRA to create a new app. And add redux.

create-react-app reduxdemo
yarn add redux

We will create a store which has a number. A reducer named countReducer updates the number when it receives an INCREMENT action. Create a new file named countReducer.js in the src folder.

export default function countReducer(state = 0, action) {
    switch(action.type) {
        case 'INCREMENT': 
            return state + 1;
        default:
            return state;
    }
}

Create the store in another file named store.js.

import countReducer from './countReducer';
import { createStore } from 'redux';

export default createStore(countReducer);

Store has three functions:

  1. getState() to get the number.
  2. dispatch() to dispatch an action.
  3. subscribe() to provide a callback when an action is processed.

We will use all three functions.

Integrate Redux with React

Open index.js which renders the App component in the document. Import the store.

import store from './store';

Move the render into a separate function.

function render() {
    ReactDOM.render(<App />, document.getElementById('root'));    
}

render();

Now comes the surprising part. When the store updates the state, we want to call the render function.

store.subscribe(render);

Would you believe it? Every time the store handles an action, we render the App component. The entire component tree is re-rendered. This is not quite obvious when we use react-reduxProvider component of react-redux does it under the covers. But there is more.

When we use connect of react-redux, there is some more magic. Modify the render function like so.

function render() {
    const count = store.getState();
    ReactDOM.render(<App count={count} />, document.getElementById('root'));    
}

We get the state stored in the store. And pass it as a prop to the App component. The connect part of react-redux does precisely that.

  1. Get the state from the store.
  2. Call mapStateToProps to get the props.
  3. Return a new component with props attached to the wrapped component.

Optimize performance

Our component tree is re-rendered every time when the store processes an action. Let’s test whether it is true. Open App.js. Add a count variable that will track the number of times the component renders.

let count = 0;

class App extends Component {

Display both the module count variable as well as the count prop in the render function.

<p className="App-intro">
  <div>render count: {++count}</div>
  {this.props.count}
</p>

Add two buttons. One to increment the count. And another to dispatch an arbitrary action.

<p className="App-intro">
  <div>render count: {++count}</div>
  {this.props.count}
  <button onClick={() => store.dispatch({ type: 'INCREMENT' })}>+1</button>
  <button onClick={() => store.dispatch({ type: 'Xyz' })}>xyz</button>
</p>

After clicking the +1 button three times and xyz button three times, our app should like so.

Component rerendered whenever store handles an action

It is easy to explain. Whenever the store handles an action, it re-renders the entire component tree. So, our App component is rendered 7 times. Please note that we dispatch an arbitrary action of xyz type. Even that re-renders the component tree. We should optimize our App component to avoid unnecessary re-render.

We do this by extending App component from PureComponentPureComponent tests if props have changed and renders only when the props have changed.

class App extends React.PureComponent {

Clicking +1 button thrice and xyz button thrice produces the desired result.

App does not render when we click xyz button

PureComponent checks if the new props are equal to the old props. It renders the component only if the props are different. Thankfully, connect of react-redux emulates the behavior of PureComponent. It re-renders the wrapped component only if the new props are different from old props.

Related Posts

Leave a Reply

Your email address will not be published.