Tuesday, May 14, 2024
 Popular · Latest · Hot · Upcoming
157
rated 0 times [  163] [ 6]  / answers: 1 / hits: 8492  / 2 Years ago, sat, november 26, 2022, 12:00:00
export default function Page({ data1 }) {
const [bookmark, setBookmark] = useState(
typeof window !== 'undefined'
? JSON.parse(localStorage.getItem('bookmark'))
: []
);

const addToBookmark = (ayatLs) => {
setBookmark([...bookmark, ayatLs]);
};

useEffect(() => {
localStorage.setItem('bookmark', JSON.stringify(bookmark));
}, [bookmark]);

return (
<>
<div className="modal-body">
<ul>
{bookmark.map((x) => (
<li key={x.nomor}>{x.tr}</li>
))}
</ul>
</div>
</>
);
}

    {data1.map((x)) => (
<div className="pb-6 flex justify-between">
<span
onClick={() => addToBookmark(x)}
className={`text-sm `}>
{x.tr}
</span>
</div>
)}

When i use typeof window !== 'undefined' the Error: Hydration failed because the initial UI does not match what was rendered on the server in my code like this.


and when i change to localStorage.getItem('bookmark') the error is localStorage is not defined


when i click addToBookmark it will store data from props data1 to localStorage, no problem here, but when I fetch the data earlier in localStorage and I want to map the data that error appears


What's wrong with my code, why can't I map data from localStorage, please help me solve this problem.


More From » reactjs

 Answers
0

The issue is that Next.js pre-renders pages by default, which means they are rendered on the server first and then sent to the client to be hydrated.


The error comes when you're setting the default value of the state based on this condition: typeof window !== 'undefined'.


Consider the following example:


const Page = () => {
const [name, setName] = useState(typeof window !== 'undefined' ? 'Peter' : 'Rick')

return <h1>{name}</h1>
}

export default Page

This code will throw an error of the type Error: Text content does not match server-rendered HTML.


If you inspect the page's source, you will see that the name rendered on the server was "Rick" while on the client-side's first render the name rendered was "Peter". There must be a match between the server-side rendered content and the client-side first render's content.


What you can do is move the localStorage data gathering and parsing logic to another useEffect instead and set the state in there. This solves the issue because useEffect only runs on the client-side, therefore you will effectively match both server-side and client-side first render content.


export default function Page({ data1 }) {
const [bookmark, setBookmark] = useState([])

const addToBookmark = (ayatLs) => {
setBookmark([...bookmark, ayatLs])
}

useEffect(() => {
if (bookmark.length === 0) return
localStorage.setItem('bookmark', JSON.stringify(bookmark))
}, [bookmark])

useEffect(() => {
const bookmarkFromLocalStorage = localStorage.getItem('bookmark')

const parsedBookmark =
bookmarkFromLocalStorage !== null
? JSON.parse(bookmarkFromLocalStorage)
: []

setBookmark(parsedBookmark)
}, [])

return (
<>
<div className='modal-body'>
<ul>
{bookmark.map((x) => (
<li key={x.nomor}>{x.tr}</li>
))}
</ul>
</div>
</>
)
}

[#9] Tuesday, August 16, 2022, 2 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
cortez

Total Points: 326
Total Questions: 106
Total Answers: 110

Location: Slovenia
Member since Wed, Apr 6, 2022
2 Years ago
cortez questions
Tue, Feb 23, 21, 00:00, 3 Years ago
Tue, Feb 23, 21, 00:00, 3 Years ago
Mon, Dec 16, 19, 00:00, 5 Years ago
Fri, Jul 12, 19, 00:00, 5 Years ago
;