Skip to content

Can cause hydration mismatch with SSR #23

Closed
@gragland

Description

@gragland

First off, really nice hook! One issue I'm seeing for SSR'ed apps is if the stored value affects DOM structure then there's going to be a hydration mismatch warning (for example Warning: Expected server HTML to contain a matching <div> in <div>).

One workaround:

export default function Todos() {
    const [query, setQuery] = useState('')
    const [todos, setTodos] = useLocalStorageState('todos', ['buy milk'])
 
    // Keep track of whether app has mounted (hydration is done)
    const [hasMounted, setHasMounted] = useState(false);
    useEffect(() => { 
        setHasMounted(true) 
    }, []);

    function onClick() {
        setTodos([...todos, query])
    }

    return (
        <>
            <input value={query} onChange={e => setQuery(e.target.value)} />
            <button onClick={onClick}>Create</button>
   
            {/* Only render todos after mount */}
            {hasMounted && todos.map(todo => (<div>{todo}</div>))}
        </>
    )
}

Maybe we can include a section in the readme that covers this? I'm not sure if there's an elegant way for the to hook to handle this. It could wait until mount to return the value from storage, but then that means an extra re-render for non-SSR apps. Thoughts?

More discussion:
https://twitter.com/gabe_ragland/status/1232055916033273858
https://www.joshwcomeau.com/react/the-perils-of-rehydration/

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions