#Loading cookies into useState

37 messages · Page 1 of 1 (latest)

slow raft
#

I'm trying to load cookie into useState. It is a simple open/closed state for a drawer made in MUI. However, with my solution it is always closed on reload and I get hydration error. The same happens when i try to do it with localStorage. I did what hydration error said I should do but it didn't help.
`const [open, setOpen] = useState(() => {
return !!(getCookie('open'))
})

const toggleDrawer = () => {
    setCookie('open', !open)
    setOpen(!open);
}

useEffect(() => {
    const openCookie = getCookie('open')
    setOpen(!!(openCookie))
},[])`
#

Error: `next-dev.js?3515:20 Warning: Prop className did not match. Server: "MuiButtonBase-root MuiIconButton-root MuiIconButton-colorInherit MuiIconButton-edgeStart MuiIconButton-sizeMedium css-dhvns5-MuiButtonBase-root-MuiIconButton-root" Client: "MuiButtonBase-root MuiIconButton-root MuiIconButton-colorInherit MuiIconButton-edgeStart MuiIconButton-sizeMedium css-1johsky-MuiButtonBase-root-MuiIconButton-root"
at button
at eval (webpack-internal:///./node_modules/@emotion/react/dist/emotion-element-
...
at Root (webpack-internal:///./node_modules/next/dist/client/index.js:346:11)

See more info here: https://nextjs.org/docs/messages/react-hydration-error`

austere compass
#

you need to start the state with an initial value and set the correct one in useEffect

#

you are receiving a hydration error because the initial value is different in the client and the server, it should be the same

slow raft
#

@austere compass I did something like
`const [open, setOpen] = useState(true)

const toggleDrawer = () => {
    setCookie('open', !open)
    setOpen(!open);
}

useEffect(() => {
    setOpen(!!(getCookie('open')))
},[])` 

and it seem to work. One downside is- if the default state is true (open drawer) and I have false in cookies it triggers transition- it is hidden shortly after refresh but I can see the transition. Is this what you meant?

austere compass
#

start with it closed

#

you could only know the value of the cookie in the server if you read it from the request, but that would require you to SSR the page

slow raft
#

@austere compass you mean something like:
`export const getServerSideProps = ({ req, res }) => {
getCookie('open', { req, res });

return { props: {} };
};` ?
I guess I could do that but my app will be heavily data based that may change quickly, you think it's a bad idea to implement SSR in that scenario?

austere compass
#

yeah something like that, you would need to return the value as a prop for the page

#

you think it's a bad idea to implement SSR in that scenario?
the answer for this question heavily depends on the project

#

if you can keep the app static it will always be cheaper and faster to serve

slow raft
#

@austere compass the app will be locally hosted, only about 15 PCs will use it, it will manage my company orders, production and warehouse, so a lot of tables that track progress of what's happening inside production cycle.

austere compass
#

hmm that seems fine to be ssr

slow raft
#

@austere compass thank you for help, have a nice day 🙂

slow raft
#

@austere compass if u have just a second, could you look at my try with ssr?

`type Props = {
children?: JSX.Element;
isOpen?: boolean;
}

export default function Layout({children, isOpen}: Props) {
const [open, setOpen] = useState(isOpen)

const toggleDrawer = () => {
    setCookie('open', !open)
    setOpen(!open);
}
return <SomeDiv/>

}

export const getServerSideProps: GetServerSideProps = ({req, res}) => {
const isOpen = getCookie('open', { req, res });
if (typeof isOpen === 'undefined') {
const isOpen = true;
}
return { props: {isOpen} };
};`

#

I get an error: TS2322: Type '({ req, res }: GetServerSidePropsContext<ParsedUrlQuery, PreviewData>) => { props: { isOpen: CookieValueTypes; }; }' is not assignable to type 'GetServerSideProps<{ [key: string]: any; }, ParsedUrlQuery, PreviewData>'.   Type '{ props: { isOpen: CookieValueTypes; }; }' is missing the following properties from type 'Promise<GetServerSidePropsResult<{ [key: string]: any; }>>': then, catch, finally, [Symbol.toStringTag]

split panther
#

Has to be async

#

Also the way you are handling the undefined case for isOpen does not work

#

You are creating a new constant in that if block and just discarding it right away

slow raft
#

@split panther the async part fixed the error message, I changed my function a bit but it always returns undefined anyway
`export const getServerSideProps: GetServerSideProps = async ({req, res}) => {
let isOpen = !!getCookie('open', { req, res });
if (typeof isOpen === 'undefined') {
return { props: { isOpen: true } };
}

return { props: { isOpen: isOpen } };

};`

split panther
#

i dont see how this returns undefined, the if clause does not make a lot of sense because you are turning isOpen into a boolean with the !! anyway

slow raft
#

@split panther I forgot you can only use getServerSideProps in \pages, I tried to use it in my Component. I'll try to move it into _app.tsx and pass the props inside my component

split panther
#

you can only use getInitialProps in _app

slow raft
#

I see. Should I use getInitialProps then on should I change my approach?

split panther
#

i personally would just use a query parameter

#

and then open the modal client side

#

or drawer

slow raft
#

@split panther not sure if I'm thinking about correct thing, I'm a newbie at nextjs- you mean query parameter as used in routing?

#

just not sure where to start

split panther
#

what is the drawer displaying? is it really important that the state is persisted?

slow raft
#

it's the app navigation (left side menu)

#

I guess it's not THAT important, it was just an idea I came up with. I'll probably have a lot of horizontal data so wanted as much screen as possible.

split panther
#

i would probably use localStorage for that then and handle it all client side

#

so the server will render the page with a closed modal, on the client side inside an effect you can check localStorage and open the drawer if its supposed to be opened

slow raft
#

I went through that solution earlier but had a problem with transitions. Since it's closed at start and useEffect sets it to open it moves at the render.

split panther
#

yea you will end up having a layout shift if you use that solution

#

if you dont want that layout shift and would not mind server side rendering a lot you can use getInitialProps