Getting Started with React and Redux: Lesson 7 of 10

Displaying Character Profiles

Up Next

Displaying a Character's World

Autoplaying in 7 seconds!

Cancel

We want to display the profile of the character. It will include their name, height, weight, homeworld, and gender.

First things first. We need to dispatch an action that will get the profile data for us and put it into state. Since we know that in the future we will be adding other actions we want to fire when a user is clicked on, we are going to make a central action that will fire other actions to get each piece of data. Add the following line to the inner function in setCharacter in our mapStateToProps in src/components/CharacterList.js file.

dispatch(getCharacterProfile(id));

Notice, we are again dispatching the result of an action creator that is receiving the id of the character that was clicked on. We also need to add this action to creator to the import at the top of the page.

Table of Contents

    import {
      setCurrentCharacter,
      getCharacterProfile,
    } from '../reducer/character/actions';

    Now, let's create this action. Add the following to src/reducer/character/actions.js.

    import { API_URL } from '../../constants';
    
    export function getCharacterProfile(id) {
      return dispatch =>
        fetch(`${API_URL}/people/${id}`)
          .then(res => res.json())
          .then(profile => {
            dispatch(setCharacterProfile(profile));
          });
    }

    We are importing our API_URL constant so we know the URL to the beginning of the API. Next, we have our getCharacterProfile action creator that is actually a thunk. Remember, when we return a function from an action creator, the middleware will pass in the dispatch function, which allows us to do some work asynchronously. We hit the SWAPI to get the profile data for the character using fetch. When it comes back, we parse the JSON, and then dispatch another action using an action creator and pass it the profile we received.

    Let's create this next action creator, setCharacterProfile. Add this to this same file.

    export const SET_CHARACTER_PROFILE = 'SET_CHARACTER_PROFILE';
    
    export function setCharacterProfile(profile) {
      return {
        type: SET_CHARACTER_PROFILE,
        profile,
      };
    }

    We just return an action that has the profile inside it.

    Now that the action is being dispatched correctly, we need a reducer that will listen for this action and will set the profile correctly in our state. Make src/reducer/character/index.js look like this.

    import { combineReducers } from 'redux';
    import id from './id';
    import profile from './profile';
    
    export default combineReducers({
      id,
      profile,
    });

    We just need to create this reducer. Put the following in a file at src/reducer/character/profile.js.

    import { SET_CHARACTER_PROFILE } from './actions';
    
    const initialState = {};
    
    export default (state = initialState, action) => {
      switch (action.type) {
        case SET_CHARACTER_PROFILE:
          return action.profile;
        default:
          return state;
      }
    };

    Here, we are simply creating a reducer that listens for our SET_CHARACTER_PROFILE and will return the profile in the action when it hears it.

    If you view things in the browser and look at the redux dev tools, you will see that the profile data is populated in our state when we click on a character. Now we just need to display it. Make your src/components/App.js look like this.

    import React from 'react';
    import CharacterList from './CharacterList';
    import CharacterProfile from './CharacterProfile';
    
    const App = () =>
      <div className='container'>
        <div className='row'>
          <CharacterList />
          <CharacterProfile />
        </div>
      </div>;
    
    export default App;

    Here, we import a component called CharacterProfile and then display it next to our CharacterList component. Let's create our component in a file at src/components/CharacterProfile.js.

    import React from 'react';
    import { connect } from 'react-redux';
    
    const CharacterProfile = ({ profile }) =>
      <div id='character-profile' className='col-md-6'>
        <h1>Profile</h1>
        {profile.name && <p>Name: {profile.name}</p>}
        {profile.height && <p>Height: {profile.height}cm</p>}
        {profile.mass && <p>Weight: {profile.mass}kg</p>}
        {profile.gender && <p>Gender: {profile.gender}</p>}
      </div>;
    
    const mapStateToProps = ({ character: { profile } }) => ({
      profile,
    });
    
    export default connect(mapStateToProps)(CharacterProfile);

    This is a pretty simple stateless component. Notice, we are using mapStateToProps again to pull the profile out of our character piece of state and pass it as a prop to our component. Our component simply checks to make sure each piece of data is set in the profile and displays it if it is.

    Load this in your browser and click on a character. You will see the profile data get populated on screen.

    Now that we have our profile showing, let's now display the data for the world that the character is originally from.

    Chris Sevilleja

    176 posts

    Founder of Scotch.io. Google Developer Expert in Web Technologies. Slapping the keyboard until something good happens.