Reputation: 7739
I have set up a Provider to share some state for a user using useContext
. As such I am trying to leverage local storage to save some state for a users images (avatars, etc.)
To start I'm tryingto persist the avatar for a user, essentially saving their ID from express and then using it when I make a call to Cloudinary (an image hosting service).
I think I'm close (as I get the default image-placeholder for the avatar to work) but I can't set the local storage.
import React, { useState, useEffect } from 'react';
import dynamic from 'next/dynamic';
var initialState = {
userId: null,
avatar: '/static/uploads/profile-avatars/placeholder.jpg'
};
var UserContext = React.createContext();
function getLocalStorage() {
return Object.keys(initialState).forEach(item => {
dynamic(
() =>
Object.keys(initialState).forEach(
val => (initialState[window.localStorage.getItem(item)] = val)
),
{
ssr: false
}
);
});
}
function setLocalStorage() {
Object.keys(initialState).forEach(item => {
console.log('item setLocalStorage', item);
dynamic(
() =>
window.localStorage.setItem(
item,
Object.values(initialState).forEach(item => item)
),
{
ssr: false
}
);
});
}
function UserProvider({ children }) {
var [userImages, setUserImages] = useState(() => getLocalStorage() || initialState);
var [userId, setUserId] = useState(userImages.userId);
useEffect(() => {
setLocalStorage();
}, [userId]);
return (
<UserContext.Provider
value={{
userImages,
setUserImages,
userId,
setUserId
}}
>
{children}
</UserContext.Provider>
);
}
export default UserContext;
export { UserProvider };
Thank you in advance, Happy Father's day!
Upvotes: 11
Views: 13952
Reputation: 4873
I believe next/dynamic
is not needed in this scenario. ES2020 dynamic import()
is for importing JavaScript modules (inc. React Components) dynamically. Here you are not importing anything.
Also, keys and values in localStorage
are always in string format. That's why you may skip null
value(or it will be converted to string "null"). I'd suggest you to store the whole user state as an object by using JSON.stringify
.
So the setLocalStorage()
and getLocalStorage()
will be:
function setLocalStorage(key, value) {
try {
window.localStorage.setItem(key, JSON.stringify(value));
} catch (e) {
// catch possible errors:
// https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API
}
}
function getLocalStorage(key, initialValue) {
try {
const value = window.localStorage.getItem(key);
return value ? JSON.parse(value) : initialValue;
} catch (e) {
// if error, return initial value
return initialValue;
}
}
Then, you may use them in the UserProvider
as followed:
function UserProvider({ children }) {
const [user, setUser] = useState(() => getLocalStorage("user", initialState));
useEffect(() => {
setLocalStorage("user", user);
}, [user]);
return (
<UserContext.Provider
value={{
userId: user.id,
userAvatar: user.avatar,
userImages: user.images,
setUserId: (id) => setUser({ ...user, id }),
setUserAvatar: (avatar) => setUser({ ...user, avatar }),
setUserImages: (images) => setUser({ ...user, images }),
}}
>
{children}
</UserContext.Provider>
);
}
Upvotes: 18