英文:
Uncaught Error: Too many re-renders. React limits the number of renders to prevent an infinite loop. (Next-js) Toggle Component
问题
以下是你要翻译的内容:
"I want to set a component to only be visible if the user wants to edit the content of an entry.
The problem is the error stated in the title.
I used setState to set a boolean @ toggle, setToggle
and then conditionally render the component UpdateReservation (at the bottom of the tsx) based off of that. Every rendered item should have it´s own button for editing.
Other solutions on here did not help. maybe i am overlooking something. Thanks in advance for the help.
This is the first part of the file:"
以下是渲染的部分:
return (
<>
<div className="flex flex-col items-center justify-around p-24 text-[#2E3A59]">
<h1 className='mt-8 text-[50px] font-bold'>Bookings</h1>
<div>
<Link href="/booking" className="m-2 flex items-center h-fit w-fit border-2 border-[#FFA500] py-1 px-4 gap-[12px] text-[20px] font-bold hover:scale-110 hover:bg-[#7EC699] hover:text-[#2E3A59] duration-300">
MAKE RESERVATION
</Link>
<div>
<div className='m-2'>
<p className='text-lg font-bold m-2'>Reservations for <strong>{format(parseISO(selectedDay), 'do MMM yyyy', { locale: de })}</strong></p>
<div className='flex flex-row'>
<button
onClick={decreaseDay}
>
-1 Day
</button>
<button
onClick={setToday}
>
TODAY
</button>
<button
onClick={increaseDay}
>
+1 Day
</button>
</div>
</div>
<p className='text-lg font-bold m-2'>Total reservations: {index}</p>
<div className='m-6 p-6 mb-12 w-[90vw] h-fit flex flex-row flex-wrap items-start flex-center'>
{sortedTables?.map((reservation) => (
<div key={reservation.id} className="m-1 p-1 border h-fit w-fit border-black">
<p className="font-bold">NAME: {reservation.name} {reservation.surname}</p>
<div className='w-full bg-black h-[2px]' />
<p><strong>email: </strong>{reservation.email}</p>
<p><strong>phone: </strong>{reservation.phone}</p>
<p><strong>Time: </strong>{format(parseISO(reservation.date), 'do MMM yyyy', { locale: de })},{format(parseISO(reservation.date), 'kk:mm', { locale: de })}</p>
<p><strong>Seats: </strong>{reservation.seats}</p>
<p className='max-w-[280px]'><strong>Message: </strong>{reservation.message}</p>
<div className='w-full bg-black h-[2px]' />
<div className='flex flex-row justify-around'>
<button
onClick={() => handleDelete(reservation.id)}
className='text-xs text-red-500 border-red-500 border-2 p-1 m-1 rounded-md hover:scale-110 duration-300 hover:text-white hover:bg-red-500'
>
Delete
</button>
<button
onClick={() => toggleEdit(reservation.id)}
className='text-xs text-green-500 border-green-500 border-2 p-1 m-1 rounded-md hover:scale-110 duration-300 hover:text-white hover:bg-green-500'
>
Edit
</button>
</div>
</div>
))}
</div>
<div>
{toggle && (
<UpdateReservation days={days} closedDays={closedDays} id={currentId} toggleEdit={toggleEdit} />
)}
</div>
</div>
</div>
</div>
</>
)
};
希望这能帮助你解决问题。
英文:
I want to set a component to only be visible if the user wants to edit the content of an entry.
The problem is the error stated in the title.
I used setState to set a boolean @ toggle, setToggle
and then conditionally render the component UpdateReservation (at the bottom of the tsx) based off of that. Every rendered item should have it´s own button for editing.
Other solutions on here did not help. maybe i am overlooking something. Thanks in advance for the help.
This is the first part of the file:
function tables({ days, closedDays }: HomeProps) {
/**
* SET STATES HERE
* @param toggle handles visibilty of UpdateReservation
* @param selectedDay is the currently selected day
*/
const [toggle, setToggle] = useState<boolean>(initToggle);
const [selectedDay, setSelectedDay] = useState<string>(initDate);
// ID OF ITEM
let currentId: string = "";
/**
* TOGGLE VISIBILITY OF UpdateReservation
* @param id is the id of the toggled reservation
*/
function toggleEdit(id: string) {
setToggle(!toggle);
currentId = id;
};
//tRPC
const { mutateAsync: addItem } = trpc.admin.bookReservation.useMutation();
const { data: reservations, refetch } = trpc.admin.getReservations.useQuery();
const { mutateAsync: updateReservation } = trpc.admin.updateReservation.useMutation();
const { mutateAsync: deleteReservation } = trpc.admin.deleteReservation.useMutation();
/**
* FUNCTIONS TO SELECT DAY
* INCREASE OR DECREASE BY 1 DAY
*/
function setToday() {
setSelectedDay(initDate);
}
function increaseDay() {
const date: Date = addDays(parseISO(selectedDay), 1);
setSelectedDay(formatISO(date));
};
function decreaseDay() {
const date: Date = subDays(parseISO(selectedDay), 1);
setSelectedDay(formatISO(date));
};
/**
* USE EFFECTS
*/
useEffect(() => {
setSelectedDay
console.log("useEffect, selectedDay");
}, [selectedDay]);
useEffect(() => {
setToggle
console.log("useEffect, setToggle");
console.log("currentId", currentId);
}, [toggle])
/**
* HANDLE DELETION OF RESERVATION
* @param id id of reservation
*/
const handleDelete = async (id: string) => {
await deleteReservation({ id });
refetch();
};
/**
* Filters reservations before rendering to only show reservations for the selected date
*/
const filterTablesByDate = reservations?.filter((reservation) => {
const formatDate: string | undefined = reservation.date.split('T')[0]
const formatSelectedDay: string | undefined = selectedDay.split('T')[0]
if (formatDate === formatSelectedDay) {
return reservation;
};
});
/**
* filteredTablesbyDate will get sorted from earliest to latest booking for the corresponding day
*/
const sortedTables = filterTablesByDate?.sort((a: any, b: any) => {
const aDate: Date = new Date(a.date);
const bDate: Date = new Date(b.date);
const aTime: number = aDate.getTime();
const bTime: number = bDate.getTime();
return aTime - bTime;
});
And this one the rendered tsx:
return (
<>
<div className="flex flex-col items-center justify-around p-24 text-[#2E3A59]">
<h1 className='mt-8 text-[50px] font-bold'>Bookings</h1>
<div>
<Link href="/booking" className="m-2 flex items-center h-fit w-fit border-2 border-[#FFA500] py-1 px-4 gap-[12px] text-[20px] font-bold hover:scale-110 hover:bg-[#7EC699] hover:text-[#2E3A59] duration-300">
MAKE RESERVATION
</Link>
<div>
<div className='m-2'>
<p className='text-lg font-bold m-2'>Reservations for <strong>{format(parseISO(selectedDay), 'do MMM yyyy', { locale: de })}</strong></p>
<div className='flex flex-row'>
<button
onClick={decreaseDay}
>
-1 Day
</button>
<button
onClick={setToday}
>
TODAY
</button>
<button
onClick={increaseDay}
>
+1 Day
</button>
</div>
</div>
<p className='text-lg font-bold m-2'>Total reservations: {index}</p>
<div className='m-6 p-6 mb-12 w-[90vw] h-fit flex flex-row flex-wrap items-start flex-center'>
{sortedTables?.map((reservation) => (
<div key={reservation.id} className="m-1 p-1 border h-fit w-fit border-black">
<p className="font-bold">NAME: {reservation.name} {reservation.surname}</p>
<div className='w-full bg-black h-[2px]' />
<p><strong>email: </strong>{reservation.email}</p>
<p><strong>phone: </strong>{reservation.phone}</p>
<p><strong>Time: </strong>{format(parseISO(reservation.date), 'do MMM yyyy', { locale: de })},{format(parseISO(reservation.date), 'kk:mm', { locale: de })}</p>
<p><strong>Seats: </strong>{reservation.seats}</p>
<p className='max-w-[280px]'><strong>Message: </strong>{reservation.message}</p>
<div className='w-full bg-black h-[2px]' />
<div className='flex flex-row justify-around'>
<button
onClick={() => handleDelete(reservation.id)}
className='text-xs text-red-500 border-red-500 border-2 p-1 m-1 rounded-md hover:scale-110 duration-300 hover:text-white hover:bg-red-500'
>
Delete
</button>
<button
onClick={() => toggleEdit(reservation.id)}
className='text-xs text-green-500 border-green-500 border-2 p-1 m-1 rounded-md hover:scale-110 duration-300 hover:text-white hover:bg-green-500'
>
Edit
</button>
</div>
</div>
))}
</div>
<div>
{toggle && (
<UpdateReservation days={days} closedDays={closedDays} id={currentId} toggleEdit={toggleEdit} />
)}
</div>
</div>
</div>
</div>
</>
)
};
export async function getServerSideProps() {
const days = await prisma.day.findMany();
const closedDays = (await prisma.closedDay.findMany()).map((d) => formatISO(d.date));
return { props: { days, closedDays } };
};
export default tables;
I tried a couple of solutions I found on here but none really made a difference. I always got the same error as mentioned in the title.
答案1
得分: 1
只是想指出,这个useEffect
会在循环中运行,因为它在依赖数组中有toggle
,而在useEffect
中,您又设置了状态setToggle
,这会再次设置toggle
并重新渲染组件。
改成这样试试:
useEffect(() => {
console.log("useEffect, setToggle");
console.log("currentId", currentId);
}, [])
英文:
Just want to point out that this useEffect will run in the loop because it has toggle in the dependency array and in the useEffect you are setting the state setToggle again which sets the toggle again and rerenders the component.
> useEffect(() => {
setToggle
console.log("useEffect, setToggle");
console.log("currentId", currentId);
}, [toggle])
Instead try this
> useEffect(() => {
setToggle
console.log("useEffect, setToggle");
console.log("currentId", currentId);
}, [])
答案2
得分: 0
不要在依赖项中放置 setState,因为这会导致重新渲染次数过多。以下是当你这样做时发生的情况分解。
首先,组件挂载并且 useEffect 运行其函数。
其次,在 useEffect 回调函数中,setState 触发并引发重新渲染。
第三,因为你将状态放在 useEffect 的依赖项中,并且在第二步中更改了它,React 将重新渲染此组件。
最后,组件再次挂载,所有这些步骤再次运行... 这就是循环的逻辑。
英文:
dont put setState in useEffect while state is in the dependencies. because this leadas to too many re-renders. here is the breakdown of whats happening when you do that.
first component mounts and useEffect runs its function.
second, in useEffect callback function setState fires and makes a re-render
third, because you put state in the dependency of useEffect and you change it in second, react will re-render this component.
finally, component again mounts and all these steps runs again ... here is the logic of the loop.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论