I'm developing an application in Next.js, and I encountered unexpected behavior. After reading a JSON file, I create a table with the information from this JSON. For each piece of information, there are additional hidden details that I need to show or hide only if the user clicks on the display buttons – Detail Button and Order Button.
In the image below, I clicked on the details of the first item in the table, and I want it to display details only for the first item. However, it starts displaying details for all other items in the table.
The relevant part of the code looks like this:
// Control visibility of information
const [isVisible2, setIsVisible2] = useState(false);
const toggleVisibility2 = () => {
setIsVisible2(!isVisible2);
}
const [isVisible1, setIsVisible1] = useState(false);
const toggleVisibility1 = () => {
setIsVisible1(!isVisible1);
}
...
// Button to display information
<button className="h-10 px-4 ..." onClick={toggleVisibility1}>
//Verificação para exibir ou não a tabela
{isVisible1 &&
<table>
<thead className="bg-slate-300">
<th className="p-3 text-sm ...">id</th>
<th className="p-3 text-sm ...">Data</th>
These elements are being mapped! There are nested mappings, as within the array of objects, we have objects that, in turn, contain other objects!
// Check to display the table or not
{isVisible1 &&
<table>
<thead className="bg-slate-300">
<th className="p-3 text-sm ...">id</th>
<th className="p-3 text-sm ...">Data</th>
</thead>
{/* Nested map for details */}
{announcements.map(announcement => (
<td>{announcement.ads_id}</td>
{/* Nested table where information needs to be hidden */}
{announcement.order_details.map(detail => (
<td>{detail.name}</td>
))}
))}
</table>
}
The application is deployed here, and the complete code is available on GitHub! The main file in this case is in the next-test/app/components/Announcements.jsx file.
Final Question: How can I display details only for the clicked button, without activating the visibility of details for all other items?
What you are doing is making every row using the same states for displaying additional info, which changing one will make everything re-render. Not the best approach but you can move the tr
out and make it a component so they can have their own state:
function TableRow({ data }) {
const [isVisible1, setIsVisible1] = useState(false);
const toggleVisibility1 = () => {
setIsVisible1(!isVisible1);
}
const [isVisible2, setIsVisible2] = useState(false);
const toggleVisibility2 = () => {
setIsVisible2(!isVisible2);
}
return (
<tr>
<td>
<button onClick={()=>toggleVisibility1()}>Toggle Info 1</button>
</td>
<td>
<button onClick={()=>toggleVisibility2()}>Toggle Info 2</button>
</td>
{isVisible1 && <table>...</table>}
{isVisible2 && <table>...</table>}
</tr>
);
}