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.
2
Answers
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.
Instead try this
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.