Redux: Updating Data on the Server

Dan Abramov
InstructorDan Abramov
Share this video with your friends

Social Share Links

Send Tweet
Published 9 years ago
Updated 6 years ago

We will learn how to wait until the item is updated on the server, and then update the corresponding local state.

[00:00] I am changing the toggle todo action creator to be a func action creator, so I'm adding dispatch as a carried argument. I'm calling the toggle todo API endpoint, and waiting for the response to come back.

[00:15] When the response is available, I will dispatch an action with the type toggle todo success, and the response. However, I will normalize the response first by passing the original response as the first argument, and the todo schema as the second argument.

[00:36] Now let's run the app. I will clear the console and toggle the todo. The UI updates when the toggle todo success action is dispatched because the action contains a normalized response in which the corresponding todo has a completed field set to true, so the ById reducer merges the new version of the todo into the current state of the lookup table.

[01:01] This is the benefit of normalizing the API responses. Updates to the entities get merged automatically. I can switch to the completed tab to verify that the server state has indeed been updated.

[01:16] I will clear the console, and then toggle the todo while I'm on the completed tab. After the toggle todo success action, the corresponding todo in the ById lookup table has been updated, and now has completed set to false. However, it is still visible in the completed list because we have not refetched it, and so its ID is still there.

[01:40] I can force refetching by going to the active tab, and then going to the completed tab back again, and it will disappear. However, I would prefer if it disappeared immediately, so I'm opening the IDs reducer in createlist.js.

[01:57] I will add a new case for the toggle todo success action. I will extract the code for this case into a separate function called handle toggle, to which I pass the state and the action.

[02:10] I'm declaring a handle toggle function above the IDs reducer. It accepts the state and a ray of IDs, and the toggle todo success action.

[02:20] I'm destructuring the result as the toggled ID and the entities from the normalized response. Next, I am reading the completed value from the todo, which I get by referencing entities todos by the toggled ID.

[02:41] There are two cases in which I want to remove the todo from the list. The first case is when the completed field is true but the filter is active, so it shouldn't be there, and the other situation is when the completed is false but the filter is completed, so we want it to disappear.

[03:00] When should remove is true, I want to return a copy of the list that does not contain the ID of the todo that was just toggled, so I filter the list by ID and only leave the ones that have a different ID. Otherwise, I return the original array.

[03:20] If I run the app now and toggle the todo while I'm on the completed tab, it will disappear right after toggle todo success action, even though we have not refetched the todos since the last time.

[03:33] Similarly, I can open the active tab and toggle a todo there. It disappears after the toggle todo success action even though the active todos have not been refetched.

[03:47] Finally, I can open the all tab and toggle the todos back and forth, and since it doesn't have any special logic, they all stay there.

[03:56] Let's recap how we handle the toggle todo success action. I extracted a function called handle toggle, and it makes sure that the toggle todo is immediately removed from the lists that shouldn't contain it.

[04:12] I'm reading the ID of the toggle todo from the result field populated by a normalizer. Next, I'm reading the completed field from the updated todo inside the todos dictionary in the normalized response.

[04:27] I want to remove the todo in two cases, if it's completed but we're looking at the list of active todos, or if it's not completed but we're looking at the list of the completed todos.

[04:40] The handle toggle function is called from the toggle todo success case inside the IDs reducer. I did not need to change any code inside the ById reducer because any updated todos get merged into the new version of the lookup table automatically.

[04:59] The only other place I needed to change is the toggle todo action creator. I change it to be a func action creator by adding a carried dispatch argument, and I made it call the toggle todo API endpoint.

[05:13] When the response is available, it dispatches the toggle todo success action, with the normalized response that I get by calling normalized with the response, and a single todo schema.

mobility-team
mobility-team
~ 8 years ago

Great journey with Redux. Incredible work you did there! Thanks Dan!

Trace Harris
Trace Harris
~ 8 years ago

I am a little confused by the implementation of

return shouldRemove ? state.filter(id => id !== toggledId) : state

in the handleToggle function

is filter referencing filter that was params prop passed by withRouter? or is it just a method on that is being used on the state object? that you passed as an argument in the handleToggle function?

Kevin Pinny
Kevin Pinny
~ 7 years ago

Great Stuff, Dan. You started losing me around lesson 19, I'm gonna read the community notes starting from those lessons to properly understand it. Thanks!

Enoh Barbu
Enoh Barbu
~ 7 years ago

if you want your todo to be visible immediately after switching from completed to active, or vice-versa, use this:

return shouldRemove? state.filter( id => id !== toggledID ) : ( filter === 'all' ? state : [...state, toggledID] );

Enoh Barbu
Enoh Barbu
~ 7 years ago

if you want your todo to be visible immediately after switching from completed to active, or vice-versa, use this:

return shouldRemove? state.filter( id => id !== toggledID ) : ( filter === 'all' ? state : [...state, toggledID] );

Enoh Barbu
Enoh Barbu
~ 7 years ago
Enoh Barbu
Enoh Barbu
~ 7 years ago
J. Matthew
J. Matthew
~ 5 years ago

is filter referencing filter that was params prop passed by withRouter? or is it just a method on that is being used on the state object? that you passed as an argument in the handleToggle function?

@Trace It's understandable to be confused by this, given the heavy use of the term filter throughout the code. In almost every instance, filter is a variable, referring either to the param passed by withRouter, as you said, or the specific filter value passed as an argument to createList.

In this case though, filter doesn't refer to either of those, but rather is a method being called on the state object passed as an argument to handleToggle, again as you said. Note that handleToggle is called inside the ids reducer, which has this signature: const ids = (state = [], action) =>. This tells us that state in this case is an array. That same state is passed to handleToggle. So when handleToggle runs this code: state.filter(id => id !== toggledId), it's using the Array.filter method. That method returns a subset of the array, made up of all elements that pass the test provided to filter. In this case, that's all the IDs that don't match the toggled one.

Markdown supported.
Become a member to join the discussionEnroll Today