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 833 of the free egghead.io lessons, plus get JavaScript content delivered directly to your inbox!



Existing egghead members will not see this. Sign in.

Just one more step!

Check your inbox for an email from us and click link to unlock your lesson.



Redux: Generating Containers with connect() from React Redux (AddTodo)

4:41 JavaScript lesson by

Learn how to inject dispatch() as a prop into a React component by using connect() from React Redux library.

Get the Code Now
click to level up

egghead.io comment guidelines

Avatar
egghead.io

Learn how to inject dispatch() as a prop into a React component by using connect() from React Redux library.

Avatar
Sequoia McDowell

Why does the AddTodo component get dispatch directly instead of a callback? Returning dispatch from mapDispatchToProps is a bit confusing... Is there any reason not to do this for consistency:

AddTodo = connect(null, dispatch => {
  return {
    onAddTodoClick : (text) => dispatch({ name : "ADD_TODO", text : text })
    // I can't see the code from here so I may have left something
    // out of that dispatch call
  };
})(AddTodo)
Avatar
Dan Abramov

Returning dispatch from mapDispatchToProps is a bit confusing

The default implementation of mapDispatchToProps, if you don’t specify it, will return just { dispatch }. I’m showing this pattern because it’s fairly common in examples, and it’s good to give it at least some exposure. In reality both styles work, and it’s really up to the person writing the code how they want to structure it.

In reply to Sequoia McDowell
Avatar
Ricardo Mayerhofer

Good, I had the same question :)

In reply to Dan Abramov

In the previous lesson, we used the connect function from ReactRedux bindings library to generate the container component that renders our presentational component. I specify how to calculate the props to inject from the current Redux store state and the callback props to inject from the dispatch function on the Redux store.

Normally, I would keep these functions, called mapStateToProps and mapDispatchToProps, but I'm working in a single file right now. I need to write these functions for if your other container components, so I'm going to rename them to something more specific, mapStateToTodoListProps and mapDispatchToTodoListProps, which you don't have to do in your code if you keep every component in its own file.

I will also remove the line breaks here to make it clear that these functions are only relevant for generating this particular container component.

Now I'm scrolling up to the AddTodo component, which is not clearly presentational or a container component. However, it uses this store. It reads this store from the context to dispatch an action when the button is clicked. It has to declare the context types to be able to grab this store from the context.

const mapStateToTodoListProps = ( ... ) => { ... }
const mapDispatchToTodoListProps = ( ... ) => { ... }

Context is an unstable API, so it's best to avoid using it in your application code. Instead of reading this store from the context, I will read the dispatch function from the props because I only need the dispatch here. I don't need the whole store.

I will create a container component with connect that will inject that the dispatch function as a prop. I will remove the contextTypes because the component generated by connect function will take care of reading this store from the context.

Because I changed the AddTodo declaration from the const to the let binding, I can reassign it now so that the consuming component does not need to specify the dispatch prop because it will be injected by the component generated by the connect call.

AddTodo = connect(

)

The first argument to the connect function is mapStateToProps, but there aren't any props for AddTodocomponent that depend on the current state, so I return an empty object. The second argument to connect is mapDispatchToProps, but AddTodo component doesn't need any callback props. It just accepts the dispatch function itself, so I'm returning it as a prop with the same name.

AddTodo = connect(
  state => {
    return {};
  },
  dispatch => {
    return { dispatch };
  }
)(AddTodo);

Finally, I'm calling the function for a second time to specify the component I want to wrap, in this case, AddTodo itself. The generated container component will not pass any props dependent on the state, but it will pass dispatch itself as a function so that the component can read from the props and use it without worrying about context or specifying contextTypes.

However, it is wasteful to even subscribe to this store if we don't calculate any props from its state. So I'm replacing the mapStateToProps function with a null, which tells connect that there is no need to subscribe to this store.

AddTodo = connect(
  null,
  dispatch => {
    return { dispatch };
  }
)(AddTodo);

Additionally, it's pretty common pattern to inject just the dispatch function. This is why if you specify null or any false value in connect as the second argument, you're going to get dispatch injected as a prop. In fact, I can just remove all arguments here. The default behavior will be to not subscribe to this store and to inject just the dispatch function as a prop.

AddTodo = connect()(AddTodo);

Let's recap what happens to the components here. The AddTodo component that I declare accepts dispatch as a prop, but it doesn't know how to get this store. It just hopes that someone is going to pass the dispatch to it.

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

  return ( ... );
};

The connect code without any arguments is going to generate a container component that does not subscribe to this store. However, that will pass dispatch to the component that it wraps. In this case, it wraps my AddTodo component.

AddTodo = connect()(AddTodo);

The second connect call returns the generated container component. I'm assigning it to AddTodo. I'm reassigning the let binding the second time.

When the further code references AddTodo, it's going to reference the container component that does not need the dispatch prop and that will pass the dispatch prop to my inner AddTodo component that I don't have a reference to anymore.

const TodoApp = () => (
  <div>
    <AddTodo />
    <VisibleTodoList />
    <Footer />
  </div>
)


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