Enter Your Email Address to Watch This Lesson

Your link to unlock this lesson will be sent to this email address.

Unlock this lesson and all 1013 of the free egghead.io lessons, plus get JavaScript content delivered directly to your inbox!



Existing egghead members will not see this. Sign in.

Redux: Extracting Action Creators

3:52 JavaScript lesson by

Learn how to keep code maintainable and self-documenting by extracting action creators from the components.

Get the Code Now
click to level up

egghead.io comment guidelines

Avatar
egghead.io

Learn how to keep code maintainable and self-documenting by extracting action creators from the components.

Avatar
Jordan

Thx for the great tutorial series! Was educational w/o being overwhelming - Russian accent was cool to listen to as well.

Avatar
Timothy

I liked how you built the exercises from plain old javascript and refactored them with higher level stuff like combineReducers, Provider, connect and mapDistpachToProps. But now as I consider building a redux app I am not going to reinvent redux as you did here. I'm going to be ->OK blank sheet->set up my workflow->? What is the story I tell myself as I set up a framework of Providers, combine reducers and connect.?

In reply to egghead.io
Avatar
Jacob

I find myself learning a new javascript framework and worrying about the css.

https://jsbin.com/pebesisaqi/edit?html,css,js,output

Avatar
Brandon

Awesome series, thanks for taking the time to make it!

Avatar
Dan Abramov

Write some components, let them dispatch actions. Write some reducers to handle those actions. Wrap some components in connect() to receive the next state. Repeat!

In reply to Timothy
Avatar
Henry Ventura

Wow. Incredible. THANK YOU!

Avatar

Very fast paced videos. I really like seeing Dan write the code for some of the objects that are in the Redux eco-system.

For those looking for a project that utilizes all these concepts in a more complex example then the ToDo, you might want to look at my Snowflake project: https://github.com/bartonhammond/snowflake - It's more complex then a Todo but not so much that you can't wrap your head around it.

Avatar
Vladimir Makushev

Just awesome, Dan! Thank you.

Avatar
Propellio

This was a wonderful and very instructive series. I really liked the approach where you implement stores and reducers via plain JS so we can see what's going on under the hood. Such simple, yet so powerful concepts. Hope you make more videos/series on React/Redux. Cheers.

Avatar
Maxi Ferreira

Fantastic series. I now feel I'm not only a better Redux developer, but also a better React developer.

Avatar
Andrew Mead

I had no idea why I'd want to use Redux when I started this course. This course really made it easy to understand the how & why of redux. Thanks Dan!

Avatar

Thanks Dan and Egghead! This course was FANTASTIC!

Dan has an incredibly relaxing voice, and I noticed that he made very few, possibly NO errors at all while typing. Kind of amazing!

Avatar
ysfzrn

Thanks for this excellent tutorial. Dan is amazing developer or creator.

Avatar
Zhentian

Thanks! This series is really great, very informative and helpful.

In reply to egghead.io
Avatar
Stefan

That was very helpful! Thank you very much!

Avatar
Alexander Hofstede

Well done, learned a lot. Might be useful to add one more; refactoring the whole thing to separate files and recommended project/folder structure?

Avatar
Abdo

Check out Stephen Grider's starter https://github.com/StephenGrider/ReduxSimpleStarter . He also has examples for his Udemy course (which I took) at https://github.com/StephenGrider/ReduxCasts

In reply to Alexander Hofstede
Avatar
Ojassvi

Thanks Dan for the excellent walk through Redux. This helps me understand the flow of data and how to think of the application.

Avatar
Sequoia McDowell

Series was great, thanks for making it! Feedbacks:

  1. Would be helpful if you highlighted places where you're doing it "wrong" but planning to rewrite it later. I struggled to understand how calling getState from render was a good idea (these frameworks are new to me so there's a lot I don't understand), only to find out that in fact that isn't a good idea & you fix it later. Big red "We're going to fix this!" note on those would help me sort out what's confusing cuz it's new from what's confusing cuz it is in fact wrong.
  2. Would love to see one or two short vids at the end breaking the application code out into a typical react/redux structure (do you group all actions in a file? etc.).
Avatar
Dan Abramov

Would be helpful if you highlighted places where you're doing it "wrong" but planning to rewrite it later. I struggled to understand how calling getState from render was a good idea

Good feedback, thanks!

Would love to see one or two short vids at the end breaking the application code out into a typical react/redux structure

I don’t have any specific file structure to suggest because I think it really depends on the app and the team, and people will repeat whatever I say even if it’s bad. So I’d rather not have any opinion at all about this.

In reply to Sequoia McDowell
Avatar
Frederic Rey

Thanks for this course!

Avatar
Nick Janssen

Very helpful tutorial series. I'm happy that you took the time to explain it at a slow pace, and summarize what happened in each lesson to really make people understand well. Thank you, I look forward to more!

Avatar
Vita

Thanks for the excellent series, really appreciate it .

Avatar
Mauro

Great stuff, thanks Dan.

Avatar
Eduardo

Could you add a video explaining how to integrate data from service and having an store that handles CRUD?

Avatar
Zane Mattingly

Great course, really helped me solidify my understanding of both Redux and React. Especially appreciated the illustration of the core Redux methods by breaking them down into vanilla JavaScript. Thanks!

Avatar
Tomás Francisco

About error handling thought redux... What is the best approach to deal with errors? Like async errors. Is a global or a scope/component handler?

Avatar
Sai

It was great Dan, Thanks a lot for this, I can't even type this message without using the backspace and I see you wrote the whole application without using the backspace even once. Pace was perfect and best part was how you wrote a native app and then improvised it.

But one thing i am not clear with is, you said not use context as it has changed earlier and will again. Then what is the best way to pass data ?

Avatar
Laurie

This course was awesome. Lots learned, lots or re-watching to really digest it and now a lifetime of application to master :D

Avatar
Andres

Great lessons. Thank you very much. Priceless!!

So far we have covered the container components, the presentational components, the reducers, and the store. But we have not covered the concept of action creators, which you might see in the Redux talks and examples.

Let's consider the following example. I dispatched the ADD_TODO action from inside the button onClick handler. This is fine. However, it references the nextTodoId variable, which added there alongside the AddTodo component.

let nextTodoId = 0;
let AddTodo = ({ dispatch }) => {
  let input;

  return (
    <div>
      <input ref={node => {
        input = node;
      }} />
      <button onClick={() => {
        dispatch({
          type: 'ADD_TODO',
          id: nextTodoId++,
          text: input.value
        })
        input.value = '';
      }}>
        Add Todo
      </button>
    </div>
  );
};

Normally, it would be local. However, what if another component wants to dispatch the ADD_TODO action? It would need to have the access to nextTodoId somehow. While I could make this variable global, it's not a very good idea.

Instead, it would be best if the components dispatching the ADD_TODO action did not have to worry about specifying the id. Because the only information they really pass is the text of the todo being added.

I don't want to generate the id inside the reducer, because that would make it non-deterministic. However, I can extract this code generating the action object into a function I will call addTodo.

<button onClick={() => {
        dispatch(addTodo(input.value));
        input.value = '';
      }}>
        Add Todo
      </button>

I pass the input value to addTodo. addTodo is just the function that takes the text of the todo and constructs an action object representing ADD_TODO action. It has the type, ADD_TODO, it takes care of generating the unique id and it includes the text.

const addTodo = (text) => {
  return {
    type: 'ADD_TODO',
    id: nextTodoId++
    text
  };
};

Although extraction such functions is not required, it is very common pattern in Redux applications to keep them maintainable, so, like all these functions, action creators, and we usually place them separately from components or from reducers.

I will now extract other action creators from the components. I see that I have setVisibilityFilter dispatch here, so I will change this to call this setVisibilityFilter action creator with ownProps.filter as the argument and is going to return the action that needs to be dispatched, so I'm declaring this setVisiblityFilter function.

const mapDispatchToLinkProps = ( ... ) => {
  onClick: () => {
    dispatch(
      setVisibilityFilter(ownProps.filter)
    );
  }
}

This is what I call an action creator, because it takes the arguments about the action and it returns the action object with the type SET_VISIBILITY_FILTER and the filter itself.

const setVisibilityFilter = (filter) => {
  return {
    type: 'SET_VISIBILITY_FILTER',
    filter
  };
};

You might think that this kind of code is boilerplate and you'd rather dispatch the action in line inside the component. However, don't underestimate how action creators document your software, because they tell your team what kinds of actions the components can dispatch, and this kind of information can be invaluable in large applications.

I will now scroll down to the last place where I call dispatch with an inline action object. I will now extract that to toggleTodo action creator, to which I pass the id of the todo as the argument.

const mapDispatchToTodoListProps = (
  dispatch
) => {
  return {
    onTodoClick: (id) => {
      dispatch(toggleTodo(id));
    }
  };
};

I'm now scrolling up to my action creators and I will add a new one that I call toggleTodo. It accepts the id as the argument and it returns the action of the type, TOGGLE_TODO, and this id.

const toggleTodo = (id) => {
  return {
    type: 'TOGGLE_TODO',
    id
  };
};

Let's take a moment to consider how convenient it is to have all the action creators in a single place so that I can use them from components and tests without worrying about the action's internal structure.

Know that whether you use action creators or not, the data flow is exactly the same, because I just call the action creator to get the action object and then I call dispatch just like I did before, passing the action.



HEY, QUICK QUESTION!
Joel's Head
Why are we asking?