-
-
Notifications
You must be signed in to change notification settings - Fork 41
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
React 18: value only is available on 2nd render cycle #56
Comments
Hi, yeah, it's by design. There is no other way to make it work when I might add this to the documentation as it's creating a lot of confusion. |
I'm having this issue with version 18 as well, using react 18 without |
Hmm. You are right. I think I actually misread the issue. I will take a look at this in the next few days. |
Hmm. Sorry. I was testing on Code Sandbox and there StrictMode is logging twice in the console (I didn't know that). I now tested this without StrictMode and can't replicate it. Can you make a reproducible example? Thanks! |
@turingmachine Can you join in? Did you figure your issue out? |
I am observing the same issue which seems to be caused by the hydration process, but in my case there are more than 1 renders before the value is finally returned. The real issue is that it is impossible to tell whether the value is not ready or the value is not there at all. So as a workaround I came up with: export function useIsLocalStorageReady() {
const [isReady, setIsReady] = useLocalStorageState("__ready");
useEffect(() => {
if (isReady) return;
setIsReady(true);
}, [isReady, setIsReady]);
return !!isReady;
} const [value, setValue] = useLocalStorageState("value");
const isLocalStorageReady = useIsLocalStorageReady();
useEffect(() => {
if (!isLocalStorageReady) return;
// now value can be read
}, [isLocalStorageReady, value]); |
@dalazx Hey, is this again with React 18? Can you do a reproduction of this? This will help me a lot! Thanks. |
@astoilkov here you go overall I think the culprit is |
You are right, the issue is If I change the code to this: import {useSyncExternalStore} from "react";
function IndexPage() {
const value = useSyncExternalStore(() => {
return () => {}
}, () => 'client value', () => 'server value')
console.log(value)
return (
<>{value}</>
);
}
export default IndexPage; Where the important part is: const value = useSyncExternalStore(() => {
return () => {}
}, () => 'client value', () => 'server value')
console.log(value) The console will log This seems like an internal React behavior. It first renders the server value and then the client value (only when it's different). A more elegant solution to your problem would be: function useIsServerRender() {
const isServerRender = useSyncExternalStore(() => {
return () => {}
}, () => false, () => true)
return isServerRender
} I will update the documentation to clarify this behavior because it's really confusing. |
It would be really nice if |
Yep, I agree. I wanted to avoid that (I would have preferred one less value to return) but it seems necessary. Can people in the discussion share why they needed to know from where the value comes? What will you do with the value? I'm asking because it's also dangerous to provide that value because the user shouldn't change the rendered HTML (React doesn't allow that). |
My use case is that I need to run the side effect only when the user has no value set in localStorage. So I have a
So for me there is no way to know if the value is I agree with you that it can be dangerous to provide this value to the user since the whole point of this two-pass rendering in strict mode is to achieve the same output between SSR and the first render. So the output between SSR and the first render must always be the same as this.
But from what I can see when I use the hook that you suggested above Alternatively, quite a nice solution can be to instead of providing a boolean value to the user with the value
|
I decided not to add a specific property for this use case. I might be wrong but it feels like an edge case. What I did instead added an explanation for the issue and how to fix it in the readme that also points to this issue. |
I believe this is by design, but can you elaborate why the value is only available on the 2nd render, which is triggered by use-local-storage-state itself?
The text was updated successfully, but these errors were encountered: