Postulate is the best way to take and share notes for classes, research, and other learning.
v0.18.2 of Postulate brought autosave to posts and snippets, so that if a user accidentally clicked out of a snippet modal or closed the tab, their work wouldn't be lost. This is implemented using useEffect
and localStorage
.
Overall design:
On data change, store data in localStorage
On load, load data from localStorage
On save, clear data from localStorage
In our Slate editor, we have a variable slateBody
that contains the user input to save. First, we add a useEffect
hook that stores the data in localStorage
when slatebody
changes. We turn slateBody
into a string because localStorage can only save strings, parsing it back into an object when we read it back.
useEffect(() => {
localStorage.setItem("postulatePostBody", JSON.stringify(slateBody));
}, [slateBody]);
Then, on state variable initialization, we simply check if there's anything in localStorage to set as the initial value; if not, we use our default initial value.
const [slateBody, setSlateBody] = useState<Node[]>(JSON.parse(localStorage.getItem("postulateSnippetBody")) || slateInitValue);
In Next.JS, this method will work if used in a component not immediately rendered, but will throw an error if used directly on a page or a component immediately rendered on a page. This is because localStorage
is undefined in an SSR environment.
To fix this, instead of looking in localStorage while initializing the state variable, we can use a useEffect
hook to set the initial state if the localStorage
variable is set:
useEffect(() => {
if (localStorage.getItem("postulatePostBody")) {
const savedSlateBody = JSON.parse(localStorage.getItem("postulatePostBody"));
setSlateBody(savedSlateBody);
}
}, []);
Finally, once the post or snippet is saved, we can clear localStorage
so that when the editor is opened again, it's blank:
localStorage.removeItem("postulateSnippetBody");
Just like that, we've implemented autosave!
Founder and dev notes from building Postulate