I would like to show/hide links depending on what the user is authorized to do. Here is my first try:
const Navbar = () => {
const { canDo, ...} = useUser(); //A Zustand store
return (
<>
<div>
<ul>
{canDo && (
<li>
<Link href="/somelink">Something</Link>
</li>
)} ...//more options
I get this error on screen load or refresh
Error: Hydration failed because the initial UI does not match what was rendered on the server.
Warning: Expected server HTML to contain a matching "li" in "ul".
Second try – useEffect
const Navbar = () => {
const Navbar = () => {
const { canDo, ...} = useUser(); //A Zustand store
var doit = false;
useEffect(() => {
doit = canDo;
}, [canDo, ...]);
<ul>
{doit && (
<li>
<Link href="/somelink">Something</Link>
</li>
This did not work – the navbar never refreshed.
The last thing I tried was to return different menus based on conditions.
That didn’t work either – I got the hydration error on refresh
The issue is the Zustand store – on a browser refresh, the store (canDo) is cleared, then reloaded. So what React rendered on the server is different than what is rendered on the client.
Any suggestions?
I did solve my problem in a very un-React type of way – in the useEffect I set/clear the display style attributes of the "li" elements. Yeah, I know – DOM manipulation in React bad.
2
Answers
This worked https://codesandbox.io/s/nextjs-zustand-example-forked-bnpfz?file=/pages/index.tsx
Page renders, the useEffect is firing, if a value inside [] of useEffect was changed, the page will be reloaded again.
Hydration error can be because your ul doesn’t contain li tags (when doit and canDo are undefined).
You can use the code from here: https://react.dev/reference/react/useEffect#fetching-data-with-effects