Reputation: 1014
I'm using a localstorage
effect as per the Recoil docs, but when i run my app i get a localStorage is not defined
error in the browser. My first assumption would be that this is not running in the browser and the server instead. I don't think this is the case, unless Next.js is doing something funky under the hood?
Here's my code:
project/recoil/atom.ts
const localStorageEffect = (key: string) => ({setSelf, onSet}: {setSelf: any, onSet: any}) => {
const savedValue = localStorage.getItem(key)
if (savedValue != null) {
setSelf(JSON.parse(savedValue));
}
onSet((newValue: any, _: null, isReset: any) => {
isReset
? localStorage.removeItem(key)
: localStorage.setItem(key, JSON.stringify(newValue));
});
};
export const userAtom = atom({
key: 'userAtom',
default: {},
effects: [
localStorageEffect('user'),
]
});
I'm trying to use it to persist login state. Here's one example of where I'm using it:
project/pages/login.tsx
const LoginPage = () => {
const [address, setAddress] = useState('');
const setUser = useSetRecoilState(userAtom);
const setIsAuthed = useSetRecoilState(isAuthedAtom);
const submitHandler = async (e: any) => {
try {
const walletInfo = await fetchWallet(address);
setIsAuthed(true);
setUser({...walletInfo, address});
} catch(e: any) {
console.log(e);
}
};
return (
<Login address={address} setAddress={setAddress} submitHandler={submitHandler} />
)
Here's _app.tsx
:
import type { AppProps } from 'next/app';
import {
RecoilRoot
} from 'recoil';
import '../styles/globals.css';
function MyApp({ Component, pageProps }: AppProps) {
return (
<RecoilRoot>
<Component {...pageProps} />
</RecoilRoot>
);
}
export default MyApp;
However, upon loading the homepage nothing will render because of the error message. I've read that a solution would be to run this in a useEffect hook, however i cannot do this since my effect is defined in atoms.ts
and cannot be moved. Is there a way to force this file to ran in the browser?
Upvotes: 2
Views: 2326
Reputation: 316
You don't need to install any other libraries, just replace this part:
import { AtomEffect } from 'recoil';
const store = typeof window !== 'undefined' ? window.localStorage : null;
export const localStorageEffect: (key: string) => AtomEffect<any> =
(key) =>
({ setSelf, onSet }) => {
if (store) {
const savedValue = store.getItem(key);
if (savedValue != null) {
setSelf(JSON.parse(savedValue));
}
onSet((newValue, _, isReset) => {
isReset ? store.removeItem(key) : store.setItem(key, JSON.stringify(newValue));
});
}
};
Upvotes: 2
Reputation: 31
Here you can try this. Worked for me
import { recoilPersist } from 'recoil-persist'
const localStorage = typeof window !== `undefined` ? window.localStorage : null
const { persistAtom } = recoilPersist({
key: 'recoil-persist',
storage: localStorage
})
export const darkModeState = atom<true | false >({
key: 'darkMode',
default: false,
effects_UNSTABLE: [persistAtom]
})
Upvotes: 3