Нестандартное раскрывающееся меню реагирования не открывается

В настоящее время у меня есть 3 строки в таблице. В каждой строке есть два столбца: имя файла и кнопка

  • Имя файла - просто фиктивная ссылка.

  • Кнопка скрывает показ меню.

Мои требования следующие:

  • Нажмите кнопку, это переключит меню. то есть, если предыдущий он близок, он должен быть открытым. Если предыдущая открыта, закройте.
  • Когда вы нажимаете на эту кнопку, если открыты другие меню, они должны быть закрыты.
  • Каждый раз открывается только 1 меню.

ссылка на github

git clone, npm install, npm start

У меня есть следующий код

import React, {useState, useEffect} from 'react'

function Menu({buttonName, menuIndex, currRowInd, setCurrRowInd}) {
  // inside menu
  const [open, setOpen] = useState(false);
  const [showMenu, setShowMenu] = useState(false);
  const menuItems = {download: 'download', view: 'view', delete: 'delete'};

  useEffect(() => {
    if (open && menuIndex === currRowInd) {
      setShowMenu(true);
    } else {
      setShowMenu(false);
    }
  }, [open, currRowInd]);

  return (
    <div>
      <button
        onClick={event => {
          // it is mouse click
          if (event.pageX !== 0 && event.pageY !== 0) {
            // toggle
            setOpen(!open);
            setCurrRowInd(menuIndex);
          }
        }}
      >
        {buttonName}
      </button>
      {showMenu && (
        <ul style={{padding: Ƌpx', margin: ཆpx', border: Ƈpx solid #ccc'}}>
          {Object.keys(menuItems).map((item, itemIndex) => {
            return (
              <li
                tabIndex="0"
                key={itemIndex}
                style={{
                  listStyle: 'none',
                  padding: Ƌpx',
                  backgroundColor: 'blue'
                }}
              >
                {item}
              </li>
            );
          })}
        </ul>
      )}
    </div>
  );
}

function TableElement() {
  const [currRowInd, setCurrRowInd] = useState('');

  const items = [
    {
      file: 'file1',
      button: 'button1'
    },
    {
      file: 'file2',
      button: 'button2'
    },
    {
      file: 'file3',
      button: 'button3'
    }
  ];
  return (
    <table style={{borderCollapse: 'collapse', border: Ƈpx solid black'}}>
      <tbody>
        {items.map((item, index) => {
          return (
            <tr key={index}>
              <td style={{border: Ƈpx solid black'}}>
                <a href="#">{item.file}</a>
              </td>
              <td style={{border: Ƈpx solid black'}}>
                <Menu
                  buttonName={item.button}
                  menuIndex={index}
                  currRowInd={currRowInd}
                  setCurrRowInd={setCurrRowInd}
                />
              </td>
            </tr>
          );
        })}
      </tbody>
    </table>
  );
}

function App() {
  return (
    <>
      <TableElement />
    </>
  );
}

export default App;

У меня есть ошибка:

  1. Нажмите кнопку 1, откроется 1-е меню (хорошо)
  2. Нажмите кнопку 2, она открывает второе меню и закрывает первое меню (хорошо)
  3. Нажмите кнопку 1 еще раз, второе меню закрывается (пока что хорошо), но первое меню не открывается.

Любая идея?

Всего 2 ответа


Вам не нужно все это состояние в компоненте Menu, это просто добавляет много сложности. Ваша проблема решается простым удалением и заменой некоторых реквизитов.

Ссылка на рабочие коды и ящик

function Menu({buttonName, showMenu, handleClick}) {
  const menuItems = {download: 'download', view: 'view', delete: 'delete'};

  return (
    <div>
      <button
        onClick={event => {
          // it is mouse click
          if (event.pageX !== 0 && event.pageY !== 0) {
            // toggle
            handleClick();
          }
        }}
      >
        {buttonName}
      </button>
      {showMenu && (
        <ul style={{padding: Ƌpx', margin: ཆpx', border: Ƈpx solid #ccc'}}>
          {Object.keys(menuItems).map((item, itemIndex) => {
            return (
              <li
                tabIndex="0"
                key={itemIndex}
                style={{
                  listStyle: 'none',
                  padding: Ƌpx',
                  backgroundColor: 'blue'
                }}
              >
                {item}
              </li>
            );
          })}
        </ul>
      )}
    </div>
  );
}

function TableElement() {
  // number is a better default. -1 will never match
  const [currRowInd, setCurrRowInd] = useState(-1);

  const items = [
    {
      file: 'file1',
      button: 'button1'
    },
    {
      file: 'file2',
      button: 'button2'
    },
    {
      file: 'file3',
      button: 'button3'
    }
  ];
  return (
    <table style={{borderCollapse: 'collapse', border: Ƈpx solid black'}}>
      <tbody>
        {items.map((item, index) => {
          return (
            <tr key={index}>
              <td style={{border: Ƈpx solid black'}}>
                <a href="#">{item.file}</a>
              </td>
              <td style={{border: Ƈpx solid black'}}>
                <Menu
                  buttonName={item.button}
                  showMenu={index === currRowInd}
                  handleClick={() => {
                    // toggle
                    if (index !== currRowInd) setCurrRowInd(index)
                    else setCurrRowInd(-1)
                  }}
                />
              </td>
            </tr>
          );
        })}
      </tbody>
    </table>
  );
}


Как уже упоминалось, вы можете значительно упростить код. Поскольку для каждой таблицы должно быть видно только одно меню, видимость должна обрабатываться для компонента TableElement .

import React, { useState } from 'react'

const Menu = ({
  buttonName,
  menuIndex,
  opened,
  handleClickButton
}) => {

  const menuItems = {
    download: 'download',
    view: 'view',
    delete: 'delete'
  };

  return (
    <div>
      <button onClick={(e) => handleClickButton(menuIndex, e)}>
        {buttonName}
      </button>

      {opened && (
        <ul style={{padding: Ƌpx', margin: ཆpx', border: Ƈpx solid #ccc'}}>
          {Object.keys(menuItems).map((item, itemIndex) => {
            return (
              <li
                tabIndex="0"
                key={itemIndex}
                style={{
                  listStyle: 'none',
                  padding: Ƌpx',
                  backgroundColor: 'blue'
                }}
              >
                {item}
              </li>
            );
          })}
        </ul>
      )}
    </div>
  );
}

const TableElement = _ => {
  const [currRowInd, setCurrRowInd] = useState(null);

  const items = [
    {
      file: 'file1',
      button: 'button1'
    },
    {
      file: 'file2',
      button: 'button2'
    },
    {
      file: 'file3',
      button: 'button3'
    }
  ];

  const handleButtonClick = (menuIndex, e) => {
    setCurrRowInd(menuIndex);
  }

  return (
    <table style={{borderCollapse: 'collapse', border: Ƈpx solid black'}}>
      <tbody>
        {items.map((item, index) => {
          return (
            <tr key={index}>
              <td style={{border: Ƈpx solid black'}}>
                <a href="#">{item.file}</a>
              </td>
              <td style={{border: Ƈpx solid black'}}>
                <Menu
                  buttonName={item.button}
                  menuIndex={index}
                  opened={currRowInd === index}
                  handleClickButton={handleButtonClick}
                />
              </td>
            </tr>
          );
        })}
      </tbody>
    </table>
  );
}

const App = _ => {
  return (
    <>
      <TableElement />
    </>
  );
}

export default App;

Есть идеи?

10000