Understanding React’s createStore, Provider, and mapStateToProps

Leo wants to incept you with some props knowledge

One of the reasons that React has become a popular JavaScript library is that it simplifies the tedium of DOM manipulation by utilizing JSX to render our elements to the page. With JSX and props, we can put any Javascript code inside any container or component and render it to the page. However, props can become problematic in complex applications where they need to be passed up and down multiple branches of a component tree.

Redux solves this problem with the introduction of the store and mapStateToProps. There are many discussions about best practices regarding when to use Redux, but I am not going to go into that in this article. To explain how mapStateToProps is used, I need to cover a few key Redux items first.

Redux introduces the concept of the store, which is just a JavaScript object that holds our state. We change our state within the store via actions (a user behavior) and reducers, which is the method we write to execute that behavior.

Building our store

How do we use the store throughout our application? First, we need to build it! I have included a basic createStore method below:

function createStore(reducer){
  let state                          <-- make variable accessible            
                                        within this method 

  function dispatch(action){         <-- dispatch updates state and                                            
    state = reducer(state, action)      renders the change
    render()
  }

  function getState(){
    return state
  }


  return {                           <-- createStore returns a JS        
    dispatch,                            object with access to these   
    getState                             two methods
  }
}


let store = createStore(<reducer>)   <-- set return value of 
store.dispatch({type: '@@INIT'})          createStore to a variable       
                                          called store. Call                          
                                          dispatch to 'set' initial 
                                          value of store.


After that, we set our state’s actual default key/value and use a switch statement with the cases we wish. Here, there is only an INCREASE_COUNT case but we can add as many as we like.

function changeCount(state = { count: 0 }, action) {
  switch (action.type) {
    case 'INCREASE_COUNT':
      return { count: state.count + 1 }

    default:
      return state;
  }
}

To render our changes to the page, we call the getState() method we wrote earlier. Since store now holds our state of the count variable, which updates a number each time we click a button.

function render() {
  let container = document.getElementById('container')

  container.textContent = store.getState().count
}
dispatch({ type: '@@INIT' }) 
let button = document.getElementById('button')

button.addEventListener('click', function() {
INCREASE_COUNT
    store.dispatch({ type: 'INCREASE_COUNT' });
})

Thankfully, we do not have to write out the createStore method from scratch inside every application. All we have to do is import it once into our top-level component and BLAMMO!, we have access to our state variables (via store) throughout our project.

Attaching it to our components

Provider is a handy tool that provides store access to each container component within the hierarchy, so we would use it at the very top. We import Provider into our project, wrap the appropriate component (often <App />), and pass our store down via props within it.

With Provider in place, the connect method comes in and says, “Put me on any component that needs access to the store!”. This method takes state as its first argument and allows us to connect the React portion of our application to the Redux portion. For the latter, connect is the only method that does this, allowing for easy translation from one library to another. Read more about what elements to connect to the store here.

Connect allows us to give our App component to part of the store’s state — the state that we mention in mapStateToProps, which is passed in as an argument. We can pass any function to connect, and the first arg will store state and then re-render the DOM each time state is changed.

You will often see the connect method used in the following contexts:

  • Syntax for importing it into a component
import { connect } from 'react-redux'
  • Used to indicate that mapStateToProps should store state and that a component should re-render when that state is updated
connect(mapStateToProps)(<Name of component>)

Speaking of mapStateToProps…

By now, we know how to set up our store and how to give parts of our application access to it. However, there is still one more piece that we need.

In React, we pass down props in order to share code between components. mapStateToProps does just what it says and is called whenever any item within that object — or “store” — is updated. However, we cannot just pass it into our connect method and move on. We need to tell it what to do!

In the code below, we tell our mapStateToProps variable to hold a function that updates our state to whatever its current value is.

const mapStateToProps = (state) => {
  return { <Your Key>: state.<Your Key> }
}

It is important to also note that you can pass in any key/value pair for your state here and Redux will always return this.props.<Name of Your Key>. If you work through your project and decide to later rename the name of the prop in your component, you will also need to change it in other components where that prop is referenced.

Read more about the mechanics of mapStateToProps and how to use it here.