Выпадающий список в React с использованием bootstrap 4

#javascript #reactjs #bootstrap-4

#javascript #reactjs #bootstrap-4

Вопрос:

Когда я нажимаю на одну ссылку выпадающего меню на панели навигации, все ссылки выпадающего меню также отображаются. Как мне это исправить, разрешив показывать только одну ссылку выпадающего меню?

Я попытался изменить значение id, которое указывает на aria-labelledby

Это состояние моего приложения

       state = {
        dropDown: false
      };


      handleDropdown = e => {
            this.setState({ dropDown: !this.state.dropDown });
        };

  

Внутри функции рендеринга

       render() {
        const { dropDown } = this.state;

      /*Conditional statement to select a class base on the state*/

      const dropMenu = dropDown ? 'dropdown-menu show' : 'dropdown-menu';

      /*The two dropdown menu list the displays(both) even when one is clicked*/

    <li className="nav-item dropdown">
                      <Link
                        onClick={this.handleDropdown}
                        className="nav-link dropdown-toggle"
                        href="#"
                        id="navbarDropdown"
                        role="button"
                        data-toggle="dropdown"
                        aria-haspopup="true"
                        aria-expanded="false"
                      >
                        Dropdown
                      </Link>
                      <div className={dropMenu} aria-labelledby="navbarDropdown">
                        <Link className="dropdown-item" to="#">
                          Action
                        </Link>
                        <Link className="dropdown-item" to="#">
                          Another action
                        </Link>
                        <div className="dropdown-divider" />
                        <Link className="dropdown-item" to="#">
                          Something else here
                        </Link>
                      </div>
                    </li>

    <li className="nav-item dropdown">
                      <Link
                        onClick={this.handleDropdown}
                        className="nav-link dropdown-toggle"
                        href="#"
                        id="navbarDropdown"
                        role="button"
                        data-toggle="dropdown"
                        aria-haspopup="true"
                        aria-expanded="false"
                      >
                        Dropdown
                      </Link>
                      <div className={dropMenu} aria-labelledby="navbarDropdown">
                        <Link className="dropdown-item" to="#">
                          Action
                        </Link>
                        <Link className="dropdown-item" to="#">
                          Another action
                        </Link>
                        <div className="dropdown-divider" />
                        <Link className="dropdown-item" to="#">
                          Something else here
                        </Link>
                      </div>
                    </li>
      };

  

Комментарии:

1. Так же, как в качестве альтернативы написанию этого вручную, вам следует использовать чужой код. reactstrap.github.io/components/navs В нем присутствуют все ранее существовавшие меню Bootstrap 4.

2. Спасибо за ресурс. Но в этом проекте я хочу использовать Bootstrap как зависимость, а не использовать пакет начальной загрузки, такой как react-bootstrap

Ответ №1:

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

 state = {
  dropDown: {
    link1: false,
    link2: false,
  }
}

handleDropdown = e => {
  const { id } = e.target;

  this.setState(prevState => ({
    dropDown : {
      ...prevState.dropDown,
      [id]: !prevState.dropDown[id],
    }
  }));
}

render() {

const { dropDown } = this.state;

      /*Conditional statement to select a class base on the state*/

      const dropMenu = dropDown ? 'dropdown-menu show' : 'dropdown-menu';

      /*The two dropdown menu list the displays(both) even when one is clicked*/

    <li className="nav-item dropdown">
                      <Link
                        onClick={this.handleDropdown}
                        className="nav-link dropdown-toggle"
                        href="#"
                        id="link1" // name your id same as the variable from state dropDown
                        role="button"
                        data-toggle="dropdown"
                        aria-haspopup="true"
                        aria-expanded="false"
                      >
                        Dropdown
                      </Link>
                      <div className={`dropdown-menu ${dropDown.link1 ? 'show' : ''}`} aria-labelledby="navbarDropdown">
                        <Link className="dropdown-item" to="#">
                          Action
                        </Link>
                        <Link className="dropdown-item" to="#">
                          Another action
                        </Link>
                        <div className="dropdown-divider" />
                        <Link className="dropdown-item" to="#">
                          Something else here
                        </Link>
                      </div>
                    </li>

    <li className="nav-item dropdown">
                      <Link
                        onClick={this.handleDropdown}
                        className="nav-link dropdown-toggle"
                        href="#"
                        id="link2" // name your id same as the variable from state dropDown
                        role="button"
                        data-toggle="dropdown"
                        aria-haspopup="true"
                        aria-expanded="false"
                      >
                        Dropdown
                      </Link>
                      <div className={`dropdown-menu ${dropDown.link2 ? 'show' : ''}`} aria-labelledby="navbarDropdown">
                        <Link className="dropdown-item" to="#">
                          Action
                        </Link>
                        <Link className="dropdown-item" to="#">
                          Another action
                        </Link>
                        <div className="dropdown-divider" />
                        <Link className="dropdown-item" to="#">
                          Something else here
                        </Link>
                      </div>
                    </li>
}

  

надеюсь, это сработает.

Ответ №2:

Обновленный код

Измените переменную состояния следующим образом:

 state = {
  dropDownState: [false, false]
};
  

Поскольку у вас их всего два li > div , массив содержит два элемента, если пункты меню увеличиваются, увеличьте и их.

Тогда div будет выглядеть как

<div className={dropMenu[0]} aria-labelledby="navbarDropdown"> и <div className={dropMenu[1]} aria-labelledby="navbarDropdown">

Каждая из привязок функций будет выглядеть следующим образом

 onClick={() => this.handleDropdown(0)}
onClick={() => this.handleDropdown(1)}
  

Затем фактическая функция изменится на

 handleDropdown = (menuIndex) => {
   let newMenuState = this.state.dropDownState.map((val, index) => {
       if(index === menuIndex) {
           return !val
       } else return val
   });

  this.setState({ dropDownState: newMenuState })
};
  

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

Старый ответ

Вместо вызова функции привяжите значение к функции:

Изменить

onClick={this.handleDropdown}

Для

onClick={() => this.handleDropdown()}

Комментарии:

1. Я попытался привязать метод, но он по-прежнему вызывал две ссылки выпадающего меню

2. Где вы используете const const dropMenu ? Я больше нигде не вижу этого в вашем коде. Разве вам не нужно использовать это как класс div внутри каждого li ? Мало того, одна переменная состояния определяет класс, который затем влияет на все подразделения внутри каждого li s (после применения const в качестве класса для div). Вам нужно сделать его динамическим с помощью массива. Каждый элемент массива будет содержать состояние для каждого li > div .

3. Ой, извините. Я только что отредактировал код. Точно, я использовал dropMenu в div внутри li, и проблема все еще существует. Пожалуйста, я не получаю путь, по которому мне нужно сделать его динамическим. Потому что const dropMenu содержит класс в зависимости от состояния выпадающего списка в функции рендеринга . Спасибо за ваше время.

4. Я приближаюсь к решению. Я console.log(dropMenu[0]), который вы использовали в элементе div в своем обновленном коде, и получил первую букву класса, которая была d (т. Е. выпадающее меню).

5. Измените <div className={dropMenu[0]} aria-labelledby="navbarDropdown"> на <div className={this.state.dropDownState[0]} aria-labelledby="navbarDropdown"> , извините, я пропустил эту часть. В основном используется элемент массива из новой переменной состояния.