Mapping State to Props in Redux
What we want to do is get access to our courses data, so it will display in our application instead of the dummy data we put in, and we can learn about that through the mapStateToProps function.
Guide Tasks
  • Read Tutorial
  • Watch Guide Video
Video locked
This video is viewable to users with a Bottega Bootcamp license

Good job in the last video, where we set up the Redux DevTools.

First off, let's close out of our open code files for now. What we want to do is get access to our courses data, so it will display in our application instead of the dummy data we put in, and we can learn about that through the mapStateToProps function.

Let's open up our library.js file, and we're going to replace null inside of it to mapStateToProps. Then we'll declare the function with an argument of state.

large

The state that we're passing in is the exact same state that shows up in the DevTools. If we were to console.log state right now, with it returning state as well, we can see that we get the data in our console.

large

As you can see, it actually logged several times, and that's because we used componentDidMount. I used this instead of componentWillMount to show that in the component Lifecycle, our mapStateToProps grabs the data to render it, but componentDidMount then runs after the data's already been rendered, which causes it to repeat the data again. Let's change the componentDidMount to componentWillMount in library.js.

This should give us access to the data we need. That data is being passed through the reducers into state. In this application, we only have the one type of action with data, but in a normal app, we may have several pieces of information coming in, so we want to make sure that we are only bringing in the course data. To do this, in library.js we can stop logging the data, and we need to only be bringing in courses.

library.js

import React, { Component } from 'react';
import { connect } from 'react-redux';

import * as actions from '../../actions';

import LibraryCourse from './libraryCourse';

class Library extends Component {

    componentWillMount() {
        this.props.fetchCourses()
    }

    render() {
        return (
            <div className="library">
                <h1 className="library__title">Course Library</h1>
                <LibraryCourse/>
                <LibraryCourse/>
                <LibraryCourse/>
            </div>
        )
    }
}

function mapStateToProps(state) {
    return {
        state.courses
    }
}

export default connect(mapStateToProps, actions)(Library);

Now that we have this being brought in, we can console.log our courses inside of our render function, so let's set our mapStateToProps to return courses: state.courses

library.js

import React, { Component } from 'react';
import { connect } from 'react-redux';

import * as actions from '../../actions';

import LibraryCourse from './libraryCourse';

class Library extends Component {

    componentWillMount() {
        this.props.fetchCourses()
    }

    render() {
        console.log(this.props.courses);
        return (
            <div className="library">
                <h1 className="library__title">Course Library</h1>
                <LibraryCourse/>
                <LibraryCourse/>
                <LibraryCourse/>
            </div>
        )
    }
}

function mapStateToProps(state) {
    return {
        courses: state.courses
    }
}

export default connect(mapStateToProps, actions)(Library);

Let's check our browser and see what we have.

large

It looks like we're getting just the course data, which is exactly what we wanted. Our next step is to now map over the course data that we have, and render it in our library. Let's work on it.

First, we can get rid of the console.log. Next we take where it says <LibraryCourse/> and we can replace those calls with { this.renderCourses() }. Now we have to build the renderCourses function. Here is what it should look like:

library.js

import React, { Component } from 'react';
import { connect } from 'react-redux';

import * as actions from '../../actions';

import LibraryCourse from './libraryCourse';

class Library extends Component {

    componentWillMount() {
        this.props.fetchCourses()
    }

    renderCourses() {
      const data = this.props.courses

      return data.map(course => {
        return <LibraryCourse/>
      })
    }

    render() {
        console.log(this.props.courses);
        return (
            <div className="library">
                <h1 className="library__title">Course Library</h1>
              { this.renderCourses() }
            </div>
        )
    }
}

function mapStateToProps(state) {
    return {
        courses: state.courses
    }
}

export default connect(mapStateToProps, actions)(Library);

As you can see, we used the map function go over the data that we have, and to put it where we need it. You should know how to use map by now since going through the pre-work and the other projects, but if you still don't understand how it works, I recommend Googling it to learn about it.

As you also may have remembered from our last project that we need to assign a key to the courses, which would be correct. I just want to show you what happens when you don't assign a key. Let's check our browser.

large

It rendered out 10 objects, but you can see that they're all identical. Plus you can see that we have an error.

large

This comes from not having an key. The application is having rouble telling one course from the others. So let's put in a key on index. So we add key={index} to our <LibraryCourse/>, then we add it to our data.map.

library.js

import React, { Component } from 'react';
import { connect } from 'react-redux';

import * as actions from '../../actions';

import LibraryCourse from './libraryCourse';

class Library extends Component {

    componentWillMount() {
        this.props.fetchCourses()
    }

    renderCourses() {
      const data = this.props.courses

      return data.map((course, index) => {
        return <LibraryCourse key={index}/>
      })
    }

    render() {
        console.log(this.props.courses);
        return (
            <div className="library">
                <h1 className="library__title">Course Library</h1>
              { this.renderCourses() }
            </div>
        )
    }
}

function mapStateToProps(state) {
    return {
        courses: state.courses
    }
}

export default connect(mapStateToProps, actions)(Library);

With that done, I'm going to go ahead and end the video here, and in the next video we'll keep working on rendering our data in our libraryCourse.js component.

Let's commit our code.

git status
git add .
git commit -m "implemented mapStateToProps and mapped over data to return the amount of course component instances we require"
git push

Resources

Code at this stage