Check out a free preview of the full Build an AI-Powered Fullstack Next.js App, v3 course

The "Autosaving Entries" Lesson is part of the full, Build an AI-Powered Fullstack Next.js App, v3 course featured in this preview video. Here's what you'd learn in this lesson:

Scott implements autosaving with the react-autosave library to save the entry content as the application state is updated. A loading state is added, and debouncing can be controlled with the interval property.


Transcript from the "Autosaving Entries" Lesson

>> Let's try to get this thing in here and saved, let's think about how we gonna save it actually, there's some behavioral stuff here. Okay, so we have the save function now inside the editor, here we go. We have the save function now, but when do we save it?

How would you say, how would anybody save this if you were making this, how would you have this be, yeah?
>> I mean, I'd probably wanna link it to a button just because you wouldn't want somebody to accidentally backspace their entire text area or actually paste something over it and then lose their entry cuz it's automatically patched through.

I'd want there to be some user validation.
>> So a manual button where you hit save?
>> Yeah.
>> Okay, that works, anybody else?
>> CRDTs obviously [LAUGH].
>> [LAUGH] Sure we definitely not doing that.
>> How long is this workshop?
>> Yeah.
>> Not long enough for that.

>> I would do either yeah button or maybe an on key up but checking what the key is to avoid something like that. Maybe both the pros, those have pros and cons.
>> Yeah, everything's a trade-off. Yeah, it's like finest line between a good user experience of this, it's just working but also being able to unstuck yourself if you just accidentally backspaced or did something.

So, having good history, there really is no right answer. In this course we're gonna do autosave, so this is going to save automatically for you. But it's not gonna be looking at key structures or anything like that, this is going to do it by state. It's gonna detect when state changes and try to debounce from that versus looking at the keystrokes.

It's not perfect but it took me five minutes to make. So, it's gonna [LAUGH] be a five-minute solution.
>> [LAUGH]
>> So, it is a good rough draft, it's like just hey, I put that PR up there, don't look at it yet though. It's just up there though, don't look, I just want you to know it's there.

But if you do look, let me know, it's one of those vibes, cool. So, in order to do that I was just gonna just create the auto save hook from scratch and I did, and then I realized it's a two-hour lecture on doing that. So, I just found a package that did almost what I wanted.

So, we're gonna install that and I believe, I forgot the name of the package now I got to go look, I believe it is called, yeah, react dash autosave. So, let's do that npm install react dash autosave. And basically, what this hook does, I can show you before we do it, is, where's an example?

Here we go, so basically what this hook does is you can call it, you can give it some data to watch. For changes, it puts that in a use effect, I'm sure and then give it a function to call when it detects a change and then you can adjust the débuts on that.

So, it's pretty trivial, but can be quite powerful. So, that's exactly what we're gonna do and then we can have a saving state to show some feedback to the user that hey, this thing is currently saving right now, and things like that. We won't handle edge cases like what happens if they start typing when it's saving and what happens if error is out while they're typing like we're not doing too much work.

I've did that for like years and it's soul crushing, [LAUGH] so I want to do that. But yeah, let's add some auto saving so I'll say use auto save like that, you can bring that in. It doesn't have a return value so it's just an object like that, and then the data prop, so what do we want to watch for changes?

Well of course, the value, whenever the value changes, because that's the thing that's being changed on change. And then on save, we can just run a function here so I'm just gonna say async. And inside here, you'll get the value that changed, right, so I'm just gonna put underscore value, is the changed value.

You could just grab the value from here, but it might be a few cycles behind in the render cycle, so it's not guaranteed to be up to date. It's the same logic from if you were to call a set value that relied on some other value, this is not guaranteed to be what you think it is.

So instead, you have to put that in a callback like this to make sure that you are on the current cycle that you think you're on cuz the reading circle might be lagging behind. So, we get the value there and then on save, we just wanna bring in our function that we made which was called update entry.

So, let's do that, so we'll say, yeah cool, let's get the entry or updated. This will be a weight update entry, it takes in an ID and some content. So, the ID It's gonna be and then the content it's gotta be underscore value. Cool, so we got that and then what do we wanna do with this update, yes?

>> I was just gonna ask if you could speak to underscore value really quick. What does that pointing to, is that pointing to the current state of the hook on eight?
>> Yeah, so underscore value and value are the same thing. They both represent the value of the text area in this case.

But the reason why we would want to use this version of it and not this version of it is because of just how react does rendering and how it does batching. If we instead use this value, okay, I'll say this, this function gets called whenever autosave detects a change from this value.

So, it detects that change and then it issues a callback on which we can then write some code in. That pretty much guarantees that we have the latest version of this value, if we use this version of it, it might not be the latest version, it could be a couple cycles behind.

Especially on something like a text editor, when someone's typing really fast, it might be a couple of keystrokes behind. So, if you use it, it'll work but you might have some issues there. So, I put underscore in front of it because it is the same thing as this, but you can't, I don't wanna, I mean this works to, I don't have to put underscore in front of it.

It will still be the same thing, I just hate doing variable shadowing like that, it's confusing. Cool, any other questions? No, okay, so we have that, the other thing to note is that okay, what do we do with the updated entry when it comes back, do we set that somewhere, like do we put that somewhere?

No, if we did that, it would mess things up because if they started typing while this was saving and then we went back and set the text area to what to save to it would erase everything they just typed. So, we don't actually wanna update the text area with an updated value.

The text area is never gonna wait on the server to update the screen, it's just gonna keep going, and it's just gonna save in the background. So yes, that does create edge cases like what if I hit back on the page before the autosave kicked in, and things like that.

So, you've gotta catch those edge cases, and there are a lot but that's what you gotta do for a great user experience, just gotta deal with those edge cases. So, right now we're not gonna do anything with it right now, but we'll get to it in a minute.

We should have a loading state though, let's do that so we can know what's going on so we can say it's loading. SetIsLoading equals useState false and then when this kicks off, we can say yeah, this thing is loading and then this thing is done we can say okay, it's done, setIsLoading to false like so.

And then we'll just throw something really ugly on the screen when something is loading. Is loading and, Load it. Cool, any questions so far, yes?
>> Is there any debouncing control with autosave or can you speak to how it would debounce?
>> Yeah, there is, what's it called, let me see, trying to get the name of the property that, this is look at the doc, so I'm trying to duck type right now use.

Use react autoSave, it does have an ability for you to pass in that time. Where is it at, interval, there it is. So, you can pass an interval. So, the number of milliseconds between save attempts. So, basically the debounce attempt by default is two seconds so you can play around with that.

If you gonna to look at the source code, which is something I always do on smaller libraries like this, it's actually really simple. So, if you go look at the use autosave component, it's just doing a few use effects, right? And it's using a use debounce hook which is probably doing some debouncing I would imagine, they created themselves.

And yeah, it's just watching that data that you gave it and it's keeping track of the functions with a ref, a ref is basically the same thing as state except for it doesn't cause a re-render. And yeah, that's it, it's actually really, really simple how they're doing it.

So, you can take a look at it if you wanna learn some more and then as far as the use deep bounce, if you wanna take a look at that, yeah, it's literally just a set timeout. So, it's a simple thing, but it's very powerful for sure, it's much simpler than what I was making, which was five times the size of that, I was getting crazy with it.

Okay, let's see what we broke, yeah? So, if I start typing something and we wait two seconds, it's gonna break or it's gonna work, we're gonna find out right now. So, let's wait two seconds, it says loading, I didn't see an error, it looked good. So, if I refresh and this still stays on the page, then it worked, looks like it did.

So that was pretty clean, that was some notion level user experience.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now