Getting Started with React and Redux: Lesson 9 of 10

Displaying a Character's Movies

Up Next

Wrapping Up

Autoplaying in 7 seconds!

Cancel

The last piece to our application is to show all the movies that the character appears in. This will be very similar to showing the character's world data. First, we need to create an action that will get the data from the SWAPI. Add the below action to src/reducer/character/actions.js.

export function getCharacterMovies(moviesUrls) {
  return dispatch =>
    Promise.all(moviesUrls.map(movieUrl =>
      fetch(movieUrl)
        .then(res => res.json())
    ))
    .then(movies =>
      dispatch(setCharacterMovies(movies))
    );
}

This action takes a list of movie URLs. We are, again, returning a thunk. It runs through each of the movie URLs and fetches the data. Each of these fetches returns a promise. Because of this, we use Promise.all to make sure we wait until they all are finished. Once they are all done, it goes to our last then callback which dispatches another action that contains all the movies. Let's add this action too.

export const SET_CHARACTER_MOVIES = 'SET_CHARACTER_MOVIES';

export function setCharacterMovies(movies) {
  return {
    type: SET_CHARACTER_MOVIES,
    movies,
  };
}

Now we need to make sure our getCharacterMovies action actually kicks off somewhere. We will do this in the same place we put our getCharacterWorld action - in getCharacterProfile.

dispatch(getCharacterMovies(profile.films));

Next, we need to create the reducer that will add this data to our state. Make src/reducer/character/index.js look like the following.

import { combineReducers } from 'redux';
import id from './id';
import profile from './profile';
import world from './world';
import movies from './movies';

export default combineReducers({
  id,
  profile,
  world,
  movies,
});

We just added a movies reducer to our character reducer. Now let's make our movies reducer at src/reducer/character/movies.js.

import { SET_CHARACTER_MOVIES } from './actions';

const initialState = [];

export default (state = initialState, action) => {
  switch (action.type) {
    case SET_CHARACTER_MOVIES:
      return action.movies.sort((ma, mb) =>
        ma.episode_id - mb.episode_id
      );
    default:
      return state;
  }
};

When we set the movies, we first sort them by episode ID. This is so we get a specific output. Now that we have the movies in state, we just need to display them. Create a new component at src/components/CharacterMovies.js and put the following in it.

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

const CharacterMovies = ({ movies }) =>
  <div id='character-movies' className='col-md-6'>
    <h1>Movies</h1>
    <ul>
      {movies.map(movie => {
        const dateArray = movie.release_date.split('-');

        return <li key={movie.title}>{movie.title} ({dateArray[0]})</li>;
      })}
    </ul>
  </div>;

const mapStateToProps = ({ character: { movies } }) => ({
  movies,
});

export default connect(mapStateToProps)(CharacterMovies);

Again, we grab the movies out of state using our trusty mapStateToProps function. They are passed into component through props. We simply iterate over them, outputting the title and the year it was released.

Last thing we need to do is add our new component to our App component. src/components/App.js should now look like this.

import React from 'react';
import CharacterList from './CharacterList';
import CharacterProfile from './CharacterProfile';
import CharacterWorld from './CharacterWorld';
import CharacterMovies from './CharacterMovies';

const App = () =>
  <div className='container'>
    <div className='row'>
      <CharacterList />
      <CharacterProfile />
    </div>
    <div className='row'>
      <CharacterWorld />
      <CharacterMovies />
    </div>
  </div>;

export default App;

View the application in the browser. Bam! Clicking on a character populates all the data in state, and React then picks this data up and displays it the way we tell it to.

Chris Sevilleja

Co-founder of Scotch.io. Slapping the keyboard until something good happens.