Hydration failed because the initial UI does not match what was rendered on the server
я впервые использую nextJS (версия 14.2.5) и столкнулся с данной проблемой: когда localStorage('todoArray') пуст ошибки нету, но когда нет то вылазит подобная ошибка. Как можно +- адекватно это пофиксить?
useTodo.ts
import React, { FormEvent, useEffect } from "react"
export interface ITodo {
id: number
title: string
description: string
}
export interface IUseTodoReturn {
functions: {
create: (title: string, description: string) => void
delete: (id: number) => void
}
get: ITodo[]
set: (array: ITodo[]) => void
}
export const useTodo = (): IUseTodoReturn => {
const [todo, setTodo] = React.useState<ITodo[]>(typeof window !== 'undefined' ? JSON.parse(localStorage.getItem('todoArray') || '[]') : [])
useEffect(() => {
localStorage.setItem('todoArray', JSON.stringify(todo))
}, [todo])
const set = (array: ITodo[]) => {
setTodo(array)
}
const createTodo = (title: string, description: string): void => {
setTodo([...todo, { id: Date.now(), title, description }])
}
const deleteTodo = (id: number) => {
const filteredArray = todo.filter(todo => todo.id !== id)
setTodo(filteredArray)
}
return {
functions: { create: createTodo, delete: deleteTodo },
get: todo,
set
}
}
'use client'
import React, { FormEvent, forwardRef, useEffect, useRef, useState } from 'react'
import { Box, Button, Stack, TextField, Typography } from '@mui/material'
import styles from './mainPage.module.scss'
import { useTodo } from '../../hooks/useTodo'
import { describe } from 'node:test'
const MainPage = () => {
const { functions, get, set } = useTodo()
const titleRef = useRef<HTMLInputElement>()
const descRef = useRef<HTMLInputElement>()
const sendTodo = (e: FormEvent) => {
e.preventDefault()
if (!titleRef.current?.value || !descRef.current?.value) return
functions.create(titleRef.current.value, descRef.current.value)
titleRef.current.value = ''
descRef.current.value = ''
}
return (
<div className={styles.root}>
<Stack className={styles.form} spacing={1} component='form' onSubmit={(e) => sendTodo(e)}>
<TextField inputRef={titleRef} sx={{ width: '30%' }} id="outlined-basic" label="Outlined" variant="outlined" />
<TextField inputRef={descRef} sx={{ width: '30%' }} id="outlined-basic" label="Outlined" variant="outlined" />
<Button sx={{ width: '30%' }} type='submit' variant='outlined'>Create</Button>
</Stack>
<Stack direction='row' gap={1} alignItems='center' justifyContent='center' className={styles.todoView}>
{get.map((todo, i) =>
<Box key={i} className={styles.todoBody}>
<Stack gap={1} flexDirection='row' alignItems='center'>
<Typography variant='h6'>{i + 1}.</Typography>
<Typography variant='h6'>{todo.title}</Typography>
</Stack>
<Typography sx={{ wordWrap: 'break-word' }}>{todo.description}</Typography>
<Button sx={{ mt: 1 }} variant='contained' onClick={() => functions.delete(todo.id)} color='error'>Delete</Button>
</Box>
)}
</Stack>
</div>
)
}
export default MainPage