1. 28
    Redux: Generating Containers with connect() from React Redux (AddTodo)
    4m 41s

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

Dan Abramov
InstructorDan Abramov
Share this video with your friends

Social Share Links

Send Tweet
Published 8 years ago
Updated 3 years ago

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

[00:00] In the previous lesson, we used the connect function from React Redux 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 chore state and the callback props to inject from the dispatch function on the Redux chore.

[00:23] Normally, I would keep these functions, call map state to props and map dispatch to props, 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, which you don't have to do in your code if you keep every component in its own file.

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

[00:54] Now I'm scrolling up to the at to-do component, which is not clearly presentational or a container component. However, it uses this chore. It reads this chore 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 chore from the context.

[01:14] Context is an unstable API, so it's best to avoid using it in your application code. Instead of reading this chore 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 chore.

[01:32] I will create a container component with connect that will inject that the dispatch function as a prop. I will remove the context types because the component generated by connect function will take care of reading this chore from the context.

[01:49] Because I changed the at to-do 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 code.

[02:07] The first argument to the connect function is map straight to props, but there aren't any props for at to-do component that depend on the current state, so I return an empty object. The second argument to connect is map dispatch to props, but at to-do 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.

[02:34] Finally, I'm calling the function for a second time to specify the component I want to wrap, in this case, at to-do 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 context types.

[03:00] However, it is wasteful to even subscribe to this chore if we don't calculate any props from its state. So I'm replacing the maps straight to props function with an O, which tells connect that there is no need to subscribe to this chore.

[03:15] 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 chore and to inject just the dispatch function as a prop.

[03:43] Let's recap what happens to the components here. The at to-do component that I declare accepts dispatch as a prop, but it doesn't know how to get this chore. It just hopes that someone is going to pass the dispatch to it.

[03:58] The connect code without any arguments is going to generate a container component that does not subscribe to this chore. However, that will pass dispatch to the component that it wraps. In this case, it wraps my at to-do component.

[04:14] The second connect call returns the generated container component. I'm assigning it to at to-do. I'm reassigning the let binding the second time.

[04:25] When the further code references at to-do, 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 at to-do component that I don't have a reference to anymore.

Sequoia McDowell
Sequoia McDowell
~ 8 years ago

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
Dan Abramov
Dan Abramovinstructor
~ 8 years ago

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.

Ricardo Mayerhofer
Ricardo Mayerhofer
~ 8 years ago

Good, I had the same question :)

Markdown supported.
Become a member to join the discussionEnroll Today