Home > Software design >  How to toggle in a map function in React?
How to toggle in a map function in React?

Time:04-20

I try to load user history and show it inside a table. Inside this table should be a button with "show more" This button is a dropdown toggle button. Everything working so far but when i click the button that is inside a map function all dropdowns open at the same time. I know i've to use an index in the map function but I've no clue how i can use this index for my dropdown state.

import React, { useEffect, useState } from 'react';
import axios from 'axios';
import { useSelector } from 'react-redux';


function OrderHistory() {
  const [history, setHistory] = useState([]);
  const [dropdown, setDropdown] = useState(false);

  const auth = useSelector((state) => state.auth);
  const token = useSelector((state) => state.token);
  const { user } = auth;

  useEffect(() => {
    const getHistory = async () => {
      const res = await axios.get('/user/history', {
        headers: { Authorization: token },
        userid: user._id,
      });
      setHistory(res.data);
    };
    getHistory();
  }, [token, setHistory]);
  console.log(history);

  const clickHandler = (index) => (event) => {
    //event.preventDefault();
    setDropdown(!dropdown);
    console.log('clicked');
  };

  return (
    <div className='history-page h-screen'>
      <h2>History</h2>
      <h4>You have {history.length} ordered</h4>

      <table>
        <thead>
          <tr>
            <th>Bestellnummer</th>
            <th>Datum</th>
            <th>Summe</th>
            <th>Details</th>
          </tr>
        </thead>
        <tbody>
          {history.map((items, index) => (
            <tr key={items._id}>
              <td>
                {items._id}
              </td>
              <td>{new Date(items.createdAt).toLocaleDateString()}</td>
              <td>
                {(
                  Math.round(
                    items.cartItems.reduce((x, item) => x   item.price, 0) * 100
                  ) / 100
                ).toFixed(2)}
                €
              </td>
              <td>
                <button
                  class='bg-yellow-500 hover:bg-yellow-400 text-white font-bold py-2 px-4 rounded'
                  key={index}
                  onClick={clickHandler(index)}
                >
                  Show more
                </button>
                <div className={dropdown ? '' : 'hidden'}>
                  <div>{items.firstName}</div>
                </div>
              </td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
}

export default OrderHistory;

CodePudding user response:

Initialize the dropdown state with null.

const [dropdown, setDropdown] = useState(null);

In clickHandler store, i just store the index.

const clickHandler = (index) => {
        setDropdown((prev) => {
            return prev === index ? null : index;
        });
        console.log('clicked', index);
    };

Now in map function, check where you apply the condition to show the dropdown. I check if the dropdown is equal to that index, then that dropdown will visible otherwise add hidden class.

You can also use _id to show/hide dropdown instead of index

<td>
    <button
        class='bg-yellow-500 hover:bg-yellow-400 text-white font-bold py-2 px-4 rounded'
        key={index}
        onClick={() => clickHandler(index)}
    >
        Show more
    </button>
    <div
        className={dropdown === index ? '' : 'hidden'}
        // style={{ display: dropdown === index ? 'block' : 'none' }}
    >
        <div>{items.firstName}</div>
    </div>
</td>
  • Related