By Marc Garreau and Will Faurot

Redux was made for React, and this article discusses how to connect them using the react-redux package.

Save 37% off Redux in Action with code fccgarreau at manning.com.

Connecting Redux and React with react-redux

Redux was built with React in mind, but they’re two totally discrete packages. To connect Redux with React, we’ll use the React bindings from the react-redux package. Redux provides only the means to configure a store. react-redux bridges the gap between React and Redux by providing the ability to enhance a component, and allows it to read state from the store or dispatch actions. react-redux gives us two primary tools for connecting our Redux store to React:

  • Provider – a React component that you’ll render at the top of the React app. Any components rendered as children of Provider can access the Redux store.

  • connect – a function used as a bridge between React components and data from the Redux store.

Adding the Provider component

Provider is a component that takes the store as a prop and wraps the top-level component in our app — in this case, App. Any child component rendered within Provider has the ability to access the Redux store, no matter how deeply nested.

In index.js, import the Provider component and wrap the App component:

Listing 1 src/index.js

  
 import React from 'react';
 import ReactDOM from 'react-dom';
 import { createStore } from 'redux';
 import { Provider } from 'react-redux';   
 import tasks from './reducers';
 import App from './App';
 import './index.css';
  
 const store = createStore(tasks);
  
 ReactDOM.render(
   <Provider store={store}>                
     <App />
   </Provider>,
   document.getElementById('root')
 );
  

Import the Provider component

Provider is now our most top-level React component. It works in conjunction with connect to make the store available to any child component

Think of the Provider component as an enabler. You won’t often interact with it directly, typically only in a file like index.js, which takes care of initially mounting the app to the DOM. Behind the scenes, Provider ensures we can use connect to pass data from the store to one or more React components.

Passing data from Redux to React components

The groundwork has been laid to pass data from the store into a React component. We have a Redux store with a tasks reducer, and we’ve used the Provider component from react-redux to make the store available to our React components. Now it’s nearly time to enhance a React component with connect.


Figure 1 The connect method bridges the gap between the store and views (components).


Generally, we can break visual interfaces into two major concerns, data and UI. In our case, the data are the JavaScript objects that represent tasks, and the UI are the few React components that take these objects and render them on the page. Without Redux, we’d deal with both of these concerns directly within React components.

As you can see in figure 2, the data we use to render our UI is moved entirely out of React and into Redux. The App component is now considered an entry point for data from Redux. As the application grows we’ll introduce more data, more UI, and as a result, more entry points. This kind of flexibility is one of Redux’s greatest strengths. Our application state lives in one place, and we can pick and choose how we want that data to flow into the application.


Figure 2 A visualization of how React and Redux work together.


In listing 2, we’re introducing a couple new concepts: connect and mapStateToProps.

By adding connect to the App component, we’ve declared it as an entry point for data from the Redux store. We’ve only connected one component here, but as our application grows we’ll start to discover best practices for when to use connect with additional components.

Here we’re passing connect a single argument, the mapStateToProps function. Note that the name mapStateToProps is a convention, not a requirement. The name stuck for a reason, because it’s an effective descriptor of the role of this function. State refers to the data in the store, and props are what get passed in to the connected component. Whatever we return from mapStateToProps is passed to our component as props.

Listing 2 src/App.js – connecting components

  
 import React, { Component } from ‘react’;
 import { connect } from ‘react-redux’;
 import TasksPage from './components/TasksPage';
   
 class App extends Component {
   render() {
     return (
       <div className="main-content">
         <TasksPage tasks={this.props.tasks} />
       </div>
     );
   }
 }
  
 function mapStateToProps(state) {   
   return {
     tasks: state.tasks              
   }
 }
  
 export default connect(mapStateToProps)(App);
  

The state argument is the entire contents of the Redux store, specifically the result of calling getState on the store instance

The return value of mapStateToProps is passed into the App component as props, which is why render is able to reference this.props.tasks

Notice how you didn’t have to update the TasksPage component? This is by design. Because TasksPage accepts its data via props, it doesn’t care about the source of those props. They could come from Redux, from React’s local state, or from another data library altogether.

Container and presentational components

Recall that TaskList is a presentational or UI component. It accepts data as props, and returns some output according to the markup you’ve defined. By using connect in the App component, we’ve secretly introduced their counterparts, known as container components.

Presentational components don’t have dependencies on Redux. They don’t know or care that we’re using Redux to manage our application state. By using presentational components, we’ve introduced determinism into our view renders. Given the same data, we’ll always have the same rendered output. Presentational components then, are easily tested and provide our application with sweet, sweet predictability.

Presentational components are great, but something needs to know how to get data out of the Redux store and pass it to our presentational components. This is where container components, like App, come in. In this simple example, they have a few responsibilities:

  • Getting data from the Redux store via connect

  • Using mapStateToProps to pass only relevant data to the component being connected

  • Rendering presentational components

Again, separating things into container and presentational components is a convention, not a hard and fast rule that React or Redux enforces.  But, it’s one of the most popular and pervasive patterns for a reason. It allows us to decouple how our app looks from what it does. Defining our UI as presentational components means we have simple, flexible building blocks which are easy to reconfigure and reuse. When we’re working with data from Redux, we can deal with container components without having to worry about markup. The inverse applies for when we’re working with UI.

At this point, we can view the data being rendered in the browser; our app is rendering a simple list of tasks retrieved from the Redux store. The next logical step would be to wire up some behavior – but that’s a topic for another time.

For more, download the free first chapter of Redux in Action.