skip to Main Content

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.

enter image description here

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?

2

Answers


  1. 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>
      );
    }
    
    Login or Signup to reply.
  2. Another approach is to use 2 arrays of booleans, one for the details table and the other for the orders table:

    const [detailVisibilityStatuses, setDetailVisibilityStatuses] = useState(
        new Array(announcements.length).fill(false)
    );
    
    const [orderVisibilityStatuses, setOrderVisibilityStatuses] = useState(
        new Array(announcements.length).fill(false)
    );
    

    Then when mapping over the announcements you can pass the index:

    {announcements.map((announcement, index) => ...
    

    You can use the index to access the status to determine whether to show the respective table:

    {detailVisibilityStatuses[index] && ...
    
    {orderVisibilityStatuses[index] && ...
    

    The index is passed to the appropriate toggle function so that the right status is updated:

    const toggleDetailVisibility = (index) => {
        const newStatuses = detailVisibilityStatuses.map((status, i) =>
          i === index ? !status : status
        );
    
        setDetailVisibilityStatuses(newStatuses);
    };
    
    const toggleOrderVisibility = (index) => {
        const newStatuses = orderVisibilityStatuses.map((status, i) =>
          i === index ? !status : status
        );
    
        setOrderVisibilityStatuses(newStatuses);
    };
    

    Here’s the updated Announcements.jsx:

    import { useState } from "react";
    
    export default function Announcements({ announcements }) {
      const [detailVisibilityStatuses, setDetailVisibilityStatuses] = useState(
        new Array(announcements.length).fill(false)
      );
    
      const [orderVisibilityStatuses, setOrderVisibilityStatuses] = useState(
        new Array(announcements.length).fill(false)
      );
    
      const toggleDetailVisibility = (index) => {
        const newStatuses = detailVisibilityStatuses.map((status, i) =>
          i === index ? !status : status
        );
    
        setDetailVisibilityStatuses(newStatuses);
      };
    
      const toggleOrderVisibility = (index) => {
        const newStatuses = orderVisibilityStatuses.map((status, i) =>
          i === index ? !status : status
        );
    
        setOrderVisibilityStatuses(newStatuses);
      };
    
      return (
        <>
          <div className="overflow-auto lg:overflow-visible rounded-lg shadow w-full pl-4 pr-4">
            <table className="w-full border-collapse">
              <thead className="bg-gray-50 border-gray-200">
                <tr>
                  <th className="title-table">Produto</th>
                  <th className="title-table">Preço</th>
                  <th className="title-table">Quantidade</th>
                  <th className="title-table">Taxa</th>
                  <th className="title-table">Shipping</th>
                </tr>
              </thead>
              <tbody className=" divide-y divide-blue-200 ">
                {announcements.map((announcement, index) => (
                  <>
                    <tr
                      key={announcement.ads_id}
                      className="hover:bg-slate-400 bg-white mb-4"
                    >
                      <td className="whitespace-nowrap lg:whitespace-normal">
                        <div className="p-2">
                          <p className="text-base font-medium">
                            {announcement.name}
                          </p>
                          <p className="text-sm">{announcement.ads_id}</p>
                          <p className="text-sm ">{announcement.sku}</p>
                          <button
                            className="h-10 px-4 mr-2 border-teal-300 border rounded-md w-24 text-sm hover:bg-blue-300"
                            onClick={() => toggleDetailVisibility(index)}
                          >
                            Detalhes
                          </button>
                          <button
                            className="h-10 px-4 mr-2 border-teal-300 border rounded-md w-24 text-sm hover:bg-blue-300"
                            onClick={() => toggleOrderVisibility(index)}
                          >
                            Pedido
                          </button>
                        </div>
                      </td>
                      <td className="text-base lg:text-lg">{announcement.value}</td>
                      <td className="text-base lg:text-lg">
                        {announcement.quantity}
                      </td>
                      <td className="text-base lg:text-lg">
                        {announcement.sale_fee}
                      </td>
                      <td className="text-base lg:text-lg">
                        {announcement.shipping_price}
                      </td>
                    </tr>
                    <tr>
                      {detailVisibilityStatuses[index] && (
                        <table>
                          <thead className="bg-slate-300">
                            <th className="title-subtable">id</th>
                            <th className="title-subtable">Data</th>
                            <th className="title-subtable">Imposto</th>
                            <th className="title-subtable">Valor Total</th>
                          </thead>
                          <tbody>
                            {announcement.orders_detail.map((detail) => (
                              <tr key={detail.order_id}>
                                <td>{detail.order_id}</td>
                                <td>{detail.date}</td>
                                <td>{detail.shipping_price}</td>
                                <td>{detail.total_value}</td>
                              </tr>
                            ))}
                          </tbody>
                        </table>
                      )}
                    </tr>
                    <tr>
                      {orderVisibilityStatuses[index] && (
                        <table>
                          <thead className="bg-slate-300">
                            <th className="title-subtable">id</th>
                            <th className="title-subtable">valor</th>
                            <th className="title-subtable">Quantidade</th>
                            <th className="title-subtable">Valor Total</th>
                            <th className="title-subtable">Taxa de Transação</th>
                            <th className="title-subtable">Imposto</th>
                          </thead>
                          <tbody>
                            {announcement.orders_group.map((group) => (
                              <tr key={group.order_id}>
                                <td>{group.order_id}</td>
                                <td>{group.value}</td>
                                <td>{group.quantity}</td>
                                <td>{group.total_value}</td>
                                <td>{group.sale_fee}</td>
                                <td>{group.shipping_price}</td>
                              </tr>
                            ))}
                          </tbody>
                        </table>
                      )}
                    </tr>
                  </>
                ))}
              </tbody>
            </table>
          </div>
        </>
      );
    }
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search