Next.js Discord

Discord Forum

cookies() bug(?)

Answered
Sloth bear posted this in #help-forum
Open in Discord
Avatar
Sloth bearOP
I found that when I need to update a cookie, the new value is passed from the server layout to the useState/useRef as an initial state from props, but its value is not being updated (I'm using router.refresh(), by the way). I'm getting the new cookie, but the old value is being preserved. If I try to pass token props from the server layout (cookie value), the authorization header preserves the old value. However, I can bypass this by manually updating useRef in a useAuth hook.
Image
Image
Answered by nevz
That's why I think the useRef solution is fine, React won't make things work unless you tell it to. So the previous videos/issue you shared aren't bugs but how React works.

If you don't tell React to re-run stuff because something has changed then it will not re-run.

So useRef is a great solution for this because of being able to keep a reference to the object
View full answer

49 Replies

Avatar
Well your client side is preserved even if you use router.refresh.

To me it seems like you don't even need a ref nor a state since the token is just a string and it comes from the server which is stable
Avatar
Sloth bearOP
No
I found the same issue
I'm getting the new token from the props (server layout), but the value is never getting updated
The problem is that everything works, but even if you initialize a state from a cookie prop — you'll anyway get old value
This is bug
Avatar
So your second snippet works right where you check if authData.current !== initialData?
Avatar
Sloth bearOP
Yes, with this hook I'm getting the new value
Avatar
So my question is do you really need a ref or a state?
Avatar
Sloth bearOP
Yes, because I need to manually update it
Otherwise I dont get the new value
Avatar
You mean you manually update it somewhere client side?
Avatar
Sloth bearOP
in the hook useAuth
Avatar
Well I don't see any other code in your authState other than replacing the ref. Here's an experiment:

In this component:
Image
Avatar
Sloth bearOP
everything works here
If i pass token from the props - value is not updated
that's the problem
Avatar
So replacving authState.current to just token does not work?
Avatar
Sloth bearOP
yes
I'm not the only one with this problem
same issue from the issues
Avatar
If you are saying that the token from the props is not updated but you get a different token in your useAuth then that doesn't really make sense to me.

Unless you haven't added the token in your useMemo dependencies array
Avatar
Sloth bearOP
Listen, everything works here with useAuth hook.
And I don't need to recreate the urql client
This is anti-pattern
The problem is that props doesn't updates useState, useRef and if I pass the token in headers
That's the problem
Avatar
Ok just to clarify:

1. You don't want to pass the token in the dependencies array because it will re-run the useMemo and re-create the client
2. You use ref so you don't need to pass it in the deps array
3. Everything works but you're trying to find if there's a better way instead of doing what you're doing at the moment?
Avatar
Sloth bearOP
You don't understand the problem
If I'll pass token manually - I don't get new value
This hook is a workaround to get the new value
And it should work without this hook
useMemo is fine
Avatar
Well the thing is with useMemo if you pass a value to it that's not in the dependencies array (which I assume you're not doing, but not clear with the screenshot since it's cut), you will not really get an updated value because it will not run because you didn't tell it to run when a value gets updated. And if you do not want this kind of solution I think your solution is already good for your use-case 🤷‍♂️

The problem is that props doesn't updates useState, useRef and if I pass the token in headers
And like I said before, even if you use router.refresh the initial data that you pass to useState or useRef will never get changed because the state is preserved meaning the state is still active even after a router.refresh

But if you think I still don't understand the problem, please share a reproducible repo just to understand clearly
And the video you shared isn't a bug, that's how it works, navigation/router refresh preserves state
Avatar
Sloth bearOP
Image
It's not about router.refresh
Avatar
Sloth bearOP
You can console.log token in graphql.ts - you are getting the new value, but if you are passing it - you don't get it
But with useAuth workaround its works
and you don't need to pass the token in the dependency array
to make it work
Avatar
Well it's using reference that's why it works, it's partly because of closures and mainly because of the object reference, but it does indeed "save" the reference in the callback function of authExchange and since callback functions can be called on-demand and it has the object reference "saved" authCurrent when the callback gets executed, it points to the correct value in memory because of it

I think it's a good solution for this use-case, you store information and read it later somewhere. Because the thing to get it work is to really pass the token in the dependencies array but that will re-run the memo which you don't want.

So there isn't really a good solution other than what you have at the moment.
Avatar
Sloth bearOP
I understand it, thanks, but why I just cannot pass it right into the headers?
Avatar
You can but again you will need to pass the token to the deps array. This is the only way you can make it work, but again this re-creates the client.

useMemo(() => {
  // ... other code
}, [token]);

Which is again important because it tells the useMemo hook that something has changed, otherwise it will not really run the useMemo if you keep it empty, it will only run once meaning it will use the old value it took from the closure not the new one. That's the thing with these dependencies array.

You can use useRef because React knows it's a stable reference that the object itself is the same object reference in memory regardless of re-renders. So it's not required in the deps array
Avatar
Sloth bearOP
It is not allowed actually. You'll get infinte loop and recreating the client is bad.
Avatar
That's why I think the useRef solution is fine, React won't make things work unless you tell it to. So the previous videos/issue you shared aren't bugs but how React works.

If you don't tell React to re-run stuff because something has changed then it will not re-run.

So useRef is a great solution for this because of being able to keep a reference to the object
Answer
Avatar
Sloth bearOP
Ok. Thanks for your time