1

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;

2
  • My only question is can we open multiple dropdowns or you just want to open one dropdown at a time? Commented Apr 19, 2022 at 13:34
  • Only one at a time Commented Apr 19, 2022 at 13:36

1 Answer 1

2

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>
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks a lot! This works fine so far. The only thing that is not working is that i can close the dropdown when i click the button again. Do you know how i can do this?
I have updated my answer. Please check the clickHandler

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.