I am having a strange issue whilst trying to implement an auto save feature to capture my controlled inputs and save them to sessionStorage().
I have an auto-save function that runs every 30 seconds. I create an object from my input values, and then save those into sessionStorage(). I run a check to see if my created object of input values matches the currently stored object. If the new object is different, I replace the current object in sessionStorage with this new object. This seems pretty straight forward to me.
What is happening, is that I am watching the sessionStorage update one character at a time, much like how the controlled inputs I am using work when setting their values from the onChange() function. Once the object is updated fully with what I typed, it resets back to being blank.
I will show an example of the described issue with the sessionStorage below the code examples.
Here is my AddPost component, that contains the 'add post' form and the auto-save function for now:
import React, { useState, useEffect } from 'react';
//Styles
import {
AddPostContainer,
AddPostInfoInput,
AddPostInfoLabel,
AddPostTextArea,
PostOptionWrapper,
PostOptionGroup,
AddPostBtn
} from './styles';
//Components
import LivePreview from './LivePreview/LivePreview';
import Icon from '../../../Icons/Icon';
const AddPost = props => {
const [htmlString, setHtmlString] = useState('');
const [title, setTitle] = useState('');
const [postBody, setPostBody] = useState('');
const [author, setAuthor] = useState('');
const [tags, setTags] = useState('');
const [featuredImage, setFeaturedImage] = useState('');
const autoSave = async () => {
const autoSaveObject = {
title,
author,
tags,
featuredImage,
postBody
};
try {
await window.sessionStorage.setItem(
'add_post_auto_save',
JSON.stringify(autoSaveObject)
);
} catch (e) {
return;
}
};
setInterval(() => {
const currentSave = window.sessionStorage.getItem('add_post_auto_save');
const autoSaveObject = {
title,
author,
tags,
featuredImage,
postBody
};
if (currentSave === JSON.stringify(autoSaveObject)) {
return;
} else {
autoSave();
}
}, 10000);
return (
<AddPostContainer>
<AddPostInfoLabel htmlFor="title">Title</AddPostInfoLabel>
<AddPostInfoInput
type="text"
value={title}
onChange={e => setTitle(e.target.value)}
placeholder="enter post title"
id="title"
/>
<AddPostTextArea
inputwidth="100%"
height="400px"
value={postBody}
onChange={e => {
setHtmlString(e.target.value);
setPostBody(e.target.value);
}}
/>
<AddPostInfoLabel htmlFor="postbody">Live Preview:</AddPostInfoLabel>
<LivePreview id="postbody" htmlstring={htmlString} />
<PostOptionWrapper>
<PostOptionGroup width="33%">
<AddPostInfoLabel htmlFor="author">Author:</AddPostInfoLabel>
<AddPostInfoInput
type="text"
value={author}
onChange={e => setAuthor(e.target.value)}
placeholder="enter author's name"
id="author"
inputwidth="60%"
/>
</PostOptionGroup>
<PostOptionGroup width="33%">
<AddPostInfoLabel htmlFor="tags">Tags:</AddPostInfoLabel>
<AddPostInfoInput
type="text"
placeholder="enter tags separated by ,"
value={tags}
onChange={e => setTags(e.target.value)}
id="tags"
inputwidth="60%"
/>
</PostOptionGroup>
<PostOptionGroup width="33%">
<AddPostInfoLabel htmlFor="featuredImage">
Feat. Image:
</AddPostInfoLabel>
<AddPostInfoInput
type="text"
placeholder="enter image url"
value={featuredImage}
onChange={e => setFeaturedImage(e.target.value)}
id="featuredImage"
inputwidth="60%"
/>
</PostOptionGroup>
</PostOptionWrapper>
<AddPostBtn type="button">
<Icon icon={['far', 'plus-square']} size="lg" pSize="1em">
<p>Add Post</p>
</Icon>
</AddPostBtn>
</AddPostContainer>
);
};
export default AddPost;
Here is the auto-save function on it's own:
const autoSave = async () => {
const autoSaveObject = {
title,
author,
tags,
featuredImage,
postBody
};
try {
await window.sessionStorage.setItem(
'add_post_auto_save',
JSON.stringify(autoSaveObject)
);
} catch (e) {
return;
}
};
setInterval(() => {
const currentSave = window.sessionStorage.getItem('add_post_auto_save');
const autoSaveObject = {
title,
author,
tags,
featuredImage,
postBody
};
if (currentSave === JSON.stringify(autoSaveObject)) {
return;
} else {
autoSave();
}
}, 30000);
This auto-save function runs once every 30 seconds, and then replaces what is in sessionStorage with what the current values for the input fields are. I use JSON.stringify() on the objects to compare them. (note: the obj from sessionStorage is already stringified.). If that match returns true, nothing is saved as the current input values are also what is saved. Else, it saves the new object into sessionStorage.
My thought was that I needed to make autoSave() async, as updating both session and local storage is asynchronous and doesn't happen immediately (although pretty close to it). That didn't work.
Here is what the sessionStorage object is when it tries to save:

It may be a lower quality, but you can see how it is updating the 'title' property. It behaves like a controlled input, character by character being added to the value.
Can someone point out what is going on here? I am at a loss on this one. Thanks in advance!