When building optimistic UIs, it's import to indicate to the user when network activity is taking place, in case there's an error or they're ready to close your app. Optimistic UIs also tend to introduce more concurrency to your application, which can making tracking the saving state more difficult. Learn how to use a simple counter to keep track of any pending requests that are currently in flight.
Sam Selikoff: [0:00] One last thing we should do is get the user an indication that their data is being saved in the background. If we were to restart the server here and use this app, it's good that it's responsive -- one, two, three, four -- and it works as fast as the user's able to type, but in the event that the network is slow or has an error, we should let the user know. Let's bring our saving state back.
[0:26] We'll setIsSaving to true at the beginning of our createTodo function and false at the end. Now if we save this and try again, we'll see we have the same problem as before since we're disabling the input when IsSaving is true. We don't need to do that anymore. In fact, nor we need to disable the input or fade it out because our UI is optimistic now.
[0:53] We have a saving indicator here in the UI. If I were to render this, we see this little cloud up here in the top right, which is a way to visually indicate that the app is saving the user's data in the background. Let's try replacing this with our isSaving flag.
[1:15] One, Two, Three, Four. You see, it seems a little inconsistent. If I were to come here and bump up the delay a little bit to two seconds for our server, and we were to try again, One, Two, Three, Four, we definitely see there's a bug, and that's because this UI is now concurrent in the sense that multiple todos can be saving at the same time.
[1:46] If we kick off the creation of one todo, it's going to setIsSaving to true and then we wait and save another one, it's going to setIsSaving to true but when the first one finishes, it's going to setIsSaving to false, even though second todo is still in flight. That's why that indicator is not really accurate right now.
[2:05] One easy way to fix this is to use an integer for our saving state instead of a Boolean. We can rename isSaving to savingCount, setIsSaving to setSavingCount, and we'll start off . Every time we create a todo, we'll go ahead and increment savingCount by 1. When that todo finishes it will decrement savingCount by 1. Now in our UI, instead of checking whether savingCount is true or false, we just need to check whether it is > .
[2:39] Let's restart our server and give it a shot. One, two, three, four, five, six. We see we have one more bug. We have a stale state bug because this savingCount refers to this one even down here in our logic after this asynchronous function has happened.
[3:07] We need to use the second version of setState that takes in the current value of savingCount in order to make sure that data is not stale. Let's update both of these calls to use savingCount the argument to make sure the logic is correct.
[3:25] Now, if we reset the server and give this a shot, one, two, three, four, five, we see our UI stays responsive even if our network is slow. This indicator always shows us whether a background save is happening or not. That is the power that comes with building optimistic UIs. We don't have to sacrifice user experience just because the network is slow.