ReactJS - допустимая функция не работает при вызове в componentDidMount() и componentDidUpdate()

******** РЕДАКТИРОВАНИЕ ДЛЯ УПРОЩЕНИЯ ПРИМЕРА И УТОЧНЕНИЯ ТРЕБОВАНИЯ И ПРОБЛЕМЫ **********

Я озадачен этим, я надеюсь, что кто-то может помочь.

У меня есть панель навигации, на которой мне нужно запустить функцию для добавления классов.active к элементам li, если у них есть потомки a.active.

Система меню является компонентом React:

import React, {Component} from "react";
import { Link, NavLink } from 'react-router-dom'

import {activateMenu} from './ActivateMenu'

class SidebarMenu extends React.Component {

  componentDidMount() {
    activateMenu()
  }

  componentDidUpdate() {
    activateMenu()
  }

  render() {

    const renderNavLink = (to, text, icon, renderArrow = false) => {
      return(
        <NavLink to={to}>
          <i className="bullet">{icon}</i>
          <span>{text}</span>
          {renderArrow ? <span className="pull-right-container">
                <i className="angle-left"><FaAngleLeft /></i>
              </span> : null}
        </NavLink>
      )
    }

    return (
      <ul className="sidebar-menu" data-widget="tree">

        <li className="">
          {renderNavLink('/','Home',<FaHome />)}
        </li>

        <li className="treeview">
          {renderNavLink("#",'Users',<FaGroup />, true)}
          <ul className="treeview-menu">
            <li>
              {renderNavLink(userSearchSlug,'Search',<FaSearch />)}
            </li>
          </ul>
        </li>
        <button onClick={activateMenu}>Press Me</button>
      </ul>
    )
  }
}

export default SidebarMenu

Это даст мне такую ​​структуру HTML:

<ul class="sidebar-menu tree" data-widget="tree">
  <li class="treeview">
    <a href="#">
      <i class="fa fa-dashboard"></i> <span>Links</span>
      <span class="pull-right-container">
            <i class="fa fa-angle-left pull-right"></i>
        </span>
    </a>
    <ul class="treeview-menu">
      <li>
        <a href="/link1"><i class="fa fa-circle-o"></i> Link1</a>
      </li>
      <li>
        <a href="/link2"><i class="fa fa-circle-o"></i> Link2</a>
      </li>
    </ul>
  </li>
</ul>

После того, как React отобразит HTML, мне нужно вызвать событие click на узле.treeview >, если какие-либо активные узлы найдены в.treeview-menu. Так: -

<li class="treeview">
    <a href="#" *****TRIGGER CLICK EVENT*****>
        <i class="fa fa-dashboard"></i> <span>Links</span>
        <span class="pull-right-container">
            <i class="fa fa-angle-left pull-right"></i>
        </span>
    </a>
    <ul class="treeview-menu">
        <li>
            <a href="/link1"><i class="fa fa-circle-o *****.ACTIVE CLASS HERE****"></i> Link1</a>
        </li>
        <li>
            <a href="/link2"><i class="fa fa-circle-o"></i> Link2</a>
        </li>
    </ul>
</li>

activeMenu () выглядит так:

$('ul.sidebar-menu li.treeview:not(.menu-open)').has('a.active').find('a').trigger( "click" );

Эта функция работает при вызове из onClick() с кнопки на странице, но она не работает в componentDidMount() и componentDidUpdate(). Функция будет работать (протестировано с console.log(), но не повлияет на HTML должным образом. Однако, если я запускаю ее из Button, она работает отлично. Она также отлично работает при запуске HMR.

Я понятия не имею, почему это происходит. У кого-нибудь есть какие-либо идеи?

1 ответ

Это, вероятно, происходит потому, что вы выбираете элемент напрямую, а не используете ссылки, хотя трудно сказать, потому что мы понятия не имеем, что $('ul.sidebar-menu .treeview a').parent().has('a.active').parent().find('.treeview a') выбирает, поэтому этот вид кода является антипаттерном.

Реакция может быть в каком-то состоянии, когда она не готова обрабатывать события щелчка в этих точках. Попробуйте использовать что-то вроде следующего:

import React, {Component} from "react";
import { Link, NavLink } from 'react-router-dom'

class SidebarMenu extends React.Component {

  constructor(props) {
    super(props);
    this.menuRefs = [];
  }

  componentDidUpdate() {
    if (this.menuRefs.length) {
      this.menuRefs[0].click();
    }
  }

  render() {

    const renderNavLink = (to, text, icon, renderArrow = false) => {
      return(
        <NavLink to={to} innerRef={ref => this.menuRefs.push(ref)}>
          <i className="bullet">{icon}</i>
          <span>{text}</span>
          {renderArrow ? <span className="pull-right-container">
                <i className="angle-left"><FaAngleLeft /></i>
              </span> : null}
        </NavLink>
      )
    }

    return (
      <ul className="sidebar-menu" data-widget="tree">

        <li className="">
          {renderNavLink('/','Home',<FaHome />)}
        </li>

        <li className="treeview">
          {renderNavLink("#",'Users',<FaGroup />, true)}
          <ul className="treeview-menu">
            <li>
              {renderNavLink(userSearchSlug,'Search',<FaSearch />)}
            </li>
          </ul>
        </li>
        <button onClick={() => this.menuRefs[0] && this.menuRefs[0].click()}>Press Me</button>
      </ul>
    )
  }
}

export default SidebarMenu

уведомление

  1. Теперь есть массив "menuRefs", и вы просто используете их как обычные элементы DOM.
  2. Мы нажимаем на menuRefs в подпорке NavLink innerRef (находится здесь)

Тем не менее, обратите внимание, что вы можете сохранить карту, чтобы гарантировать, что дубликаты не будут вставлены в menuRefs.

Чтобы узнать больше о ссылках, посетите документы: https://reactjs.org/docs/refs-and-the-dom.html

Другие вопросы по тегам