Video Course

Getting Started with React and Redux: Lesson 6 of 10

Dispatching on Click

Up Next

Displaying Character Profiles

Autoplaying in 7 seconds!

Cancel

We have all our characters. Now, we need to be able to click on a character and get the rest of their data. Let's first create the reducer that will handle updating our state. We will keep it simple for this one and just add the currently selected character's id in our state. We are going to keep this at character.id. Make src/reducer/index.js look like the following.

import { combineReducers } from 'redux';
import characters from './characters';
import character from './character';

export default combineReducers({
  characters,
  character,
});

We brought in another reducer and included it in our main piece of state. Let's create the character reducer, which will just be a combined reducer from the reducers that will be in it. Create a file at src/reducer/character/index.js and put this in it.

import { combineReducers } from 'redux';
import id from './id';

export default combineReducers({
  id,
});

Like in the main reducer, this reducer is just a combination of other reducers. We have already included one that will handle adding the currently selected character's ID to our state. Create a file at src/reducer/character/id.js and put the following in it.

import { SET_CURRENT_CHARACTER } from './actions';

const initialState = 0;

export default (state = initialState, action) => {
  switch (action.type) {
    case SET_CURRENT_CHARACTER:
      return action.id;
    default:
      return state;
  }
};

We bring in an action constant. The initial state of our character's ID is just zero. If an action comes in that has the type matching our constant of SET_CURRENT_CHARACTER, we will grab the id out of the action and return it. Otherwise, we just return the passed in state.

Let's create this constant. Create a file at src/reducer/character/actions.js and put the following in it.

export const SET_CURRENT_CHARACTER = 'SET_CURRENT_CHARACTER';

Everything should now build fine, but we still aren't firing an action off at all. Let's create that action that will be dispatched to the store when the character's name is clicked. Add the following to the file at src/reducer/character/actions.js.

export function setCurrentCharacter(id) {
  return {
    type: SET_CURRENT_CHARACTER,
    id,
  };
}

This action creator simply returns an action that has the characters ID in it. Now we need to dispatch this action when a character is clicked on. Back in our src/components/CharacterList.js file, we need to add another function to the bottom. the connect function takes a second argument. This second argument is a function that will be passed the dispatch function from the store. We need to return an object of functions that will then be passed to our stateless function as props. We can use these props as the callbacks for our onClick event handlers. Let's create a new function called mapDispatchToProps and make it look like the following.

const mapDispatchToProps = dispatch => ({
  setCharacter(id) {
    return () => {
      dispatch(setCurrentCharacter(id));
    };
  },
});

This function takes in the dispatch function and returns an object with a single function on it. This setCharacter function takes an id and returns another function. This inner function will be the function called when a user clicks on a character. The function simply creates an action using our setCurrentCharacter action creator and then dispatches that action to the store. Since we already created the reducer that handles this action, we know what it will do already!

Now we need to add this function to our connect call. It should now look like this.

export default connect(mapStateToProps, mapDispatchToProps)(CharacterList);

We also have forgotten to import our action creator. So let's do this now. Add this to the top of your file.

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

Now, we need to bring our event handler into our component. Make the component signature look like the below.

const CharacterList = ({ characters, setCharacter }) =>

Lastly, we need to make sure we fire this function whenever we click on a character. Our characters map function should now look like this.

{characters.map((c, i) =>

    {c.name}

)}

Notice we are invoking setCharacter instead of just passing the function without invoking it. This is because we want to make sure the ID is around after the loop runs. Closures to the rescue!

Refresh your page and you should see...nothing has changed. Well, that's not completely true. If you look at our current state in the redux dev tools, you will see that when you click on a character, the updated in state. Sweet!

In the next one, we will do a similar process, but we will actually get some data and display it on the page.

Chris Sevilleja

164 posts

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