astoilkov / use-local-storage-state

React hook that persists data in localStorage
MIT License
1.09k stars 39 forks source link

Seems to be trying to fetch from local storage before window is defined in React/Next SSR environment #55

Closed gDub74 closed 1 year ago

gDub74 commented 1 year ago

I'm using use-local-storage-stare in a custom hook to store a UUID in local storage. I'm calling my hook in several places in the app and I can see that when the window is undefined that I get different UUIDs from my default setting until window is defined and then I get the correct UUID from storage returned. Here is my implementation:

`import useLocalStorageState from "use-local-storage-state"; import { v4 as uuid } from "uuid";

const LOCAL_STORAGE_KEY = "RESONANCE_DEVICE_ID";

const useDeviceId = (): string | undefined => { const [deviceId] = useLocalStorageState(LOCAL_STORAGE_KEY, { defaultValue: uuid(), });

return deviceId;

};

export default useDeviceId; `

and I'm on React 18.2.0, Next 12.2.2 , use-local-storage-state 18.1.0 logging on Server (note different id being generated by default UUID() since window is still undefined at this point (best guess). image

logging on client: can see that the id from storage comes through after first 2 defaults get created. image

Question, is there a way to disable until window is defined? An option something like { useSSR: false } or similar?

Thank you!

astoilkov commented 1 year ago

What do you mean by "disable"? You can't skip the execution of the hook. That's a limitation of React Hooks. However, you can return undefined when the window is not available (by not providing a defaultValue) and check that in your code:

import useLocalStorageState from "use-local-storage-state";
import { v4 as uuid } from "uuid";

const LOCAL_STORAGE_KEY = "RESONANCE_DEVICE_ID";

const useDeviceId = (): string | undefined => {
  const [deviceId] = useLocalStorageState(LOCAL_STORAGE_KEY);

  return deviceId;
};

export default useDeviceId;
gDub74 commented 1 year ago

Thanks for the info! That doesn't quite work for my use case since I only want to read/set local storage after window is defined. I was hoping there was a way to not fire off the default until window is defined, I can handle in a useEffect conditionally... Just was thinking you already had this case covered since the description of the package says SSR support.

Curious, how is it supported for SSR?

Thanks again!

astoilkov commented 1 year ago

What do you think useLocalStorageState should return while the window is not defined?

Curious, how is it supported for SSR?

The SSR support in React 18 is just a single line of code: https://github.com/astoilkov/use-local-storage-state/blob/b3cfa46927a27c282685a6790fd5400a9b48c64f/src/useLocalStorageState.ts#L159

It just provides a value to getServerSnapshot. That's the built-in way for React 18 to handle SSR.

gDub74 commented 1 year ago

I agree that returning undefined when window is not defined is a good idea. Just was thinking the setting of the default could be handled after the window is defined (as SSR support). I don't see the value of setting the default if no window, because there could already be a value in storage and then it will potentially change if that value is different from default..

astoilkov commented 1 year ago

Do you have ideas of how this could be implemented inside of use-local-storage-state?

gDub74 commented 1 year ago

Sorry for the trouble, I miss understood the purpose of your the use-local-storage-state hook w/ regards to SSR. I will make a small wrapper for my use case.