Событие onClick не срабатывает на функциональном элементе

На всю жизнь я не могу понять, почему событие щелчка не срабатывает в моем функциональном компоненте.

Вот мой компонент:

import React, { useState, useEffect } from 'react';
import {
    Collapse,
    Navbar,
    NavbarToggler,
    Nav,
    NavItem,
    NavLink,
} from 'reactstrap';

import classNames from 'classnames';
import img from '../../img/logo/logo-white.svg';

const NavBar = () => {
    const [isOpen, setIsOpen] = useState(false);
    const toggle = () => {
        console.log('toggllling', isOpen);
        setIsOpen(!isOpen);
    };

    return (
        <div
            id="nav-wrap"
            className={classNames({ 'bg-dark-blue': isOpen })}
        >
            <Navbar color="transparent" dark expand="lg" className="container">
                <a className="navbar-brand" href="/">
                    <img alt="logo light" src={img} />
                </a>
                <NavbarToggler onClick={toggle} />
                <Collapse isOpen={isOpen} navbar>
                    <Nav className="navbar-nav" navbar>
                        <NavItem className="active">
                            <NavLink href="/">First</NavLink>
                        </NavItem>
                        <NavItem>
                            <NavLink href="/">second</NavLink>
                        </NavItem>
                        <NavItem>
                            <NavLink href="/">Thord</NavLink>
                        </NavItem>
                        <NavItem className="separated">
                            <NavLink href="/">Fourth</NavLink>
                        </NavItem>
                        <NavItem>
                            <NavLink href="/">fifth</NavLink>
                        </NavItem>
                        <NavItem>
                            <NavLink href="/" className="btn btn-light">last</NavLink>
                        </NavItem>
                    </Nav>
                </Collapse>
            </Navbar>
        </div>
    );
};

export default NavBar;

Это немного более продвинутая версия примера переключения панели навигации со страницы reactstrap: https://reactstrap.github.io/components/navbar/

Из React Devtools я вижу, что событие привязано к правильному компоненту реакции. Если я заменю toggle чем-то, что должно срабатывать немедленно, как вызов функции, то он срабатывает немедленно. Но когда я нажимаю на настоящую кнопку, ничего не происходит. Я даже привязал событие щелчка к документу, чтобы увидеть, есть ли что-то скрытое над кнопкой, и вышел из системы, если событие распространяется на правильный элемент - так оно и было. так что, убей меня, я не могу понять, почему функция переключения никогда не срабатывает и почему я никогда не вижу «переключение» в своей консоли. Я также пытался добавить этот onClick к любому другому элементу в компоненте, и он никогда не работает внутри компонента.

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

ready(() => {
    // Example:
    const wrap = document.getElementById('nav-wrap');
    if (wrap) {
        // perform element replacement
        const parent = wrap.parentNode;
        const temp = document.createElement('div');
        render(<NavBar element={wrap} />, temp);
        parent.replaceChild(temp.querySelector('div#nav-wrap'), wrap);
    }
});

Редактировать:

Я упростил компонент, и результаты те же — событие не срабатывает. Когда я отлаживаю его с помощью инструментов разработчика браузера и добавляю точку останова по щелчку мыши, я вижу, что вызов функции заканчивается в react-dom.development.js function noop() {} Почему это так?


person Odif Yltsaeb    schedule 10.02.2021    source источник
comment
В этом коде так много красных флажков, например, добавление события при каждом рендеринге и запрос DOM, который является анти-шаблоном (используйте ref), если вы хотите, чтобы он был решен, вы должны УПРОСТИТЬ этот код до минимального примера Как создать минимальный воспроизводимый пример   -  person Dennis Vash    schedule 10.02.2021
comment
Я не уверен, как работает ваш Collapse, но если коллапс запускает какой-то слушатель в вашем useEffect, то ваш isOpen снова становится ложным. Я попытаюсь закомментировать предложение useEffect, чтобы увидеть, работает ли переключатель.   -  person Someone Special    schedule 10.02.2021
comment
@DennisVash запрашивает дом - да, я мог бы удалить его из примера. Единственная причина, по которой эта часть существует, заключается в повторном использовании кода, уже находящегося в шаблоне, который компонент в конечном итоге заменяет. Это не SPA-приложение и должно работать даже без JS. Но что вы имеете в виду под присоединением события к каждому рендеру? Я чувствую, что здесь что-то упускаю. Разве это не то же самое, что здесь: событие reactstrap.github.io/components/navbar прикрепляется к возвращаемому коду, и код перерисовывается только в случае изменения isopen. Но попробую упростить. Это хорошее предложение.   -  person Odif Yltsaeb    schedule 10.02.2021
comment
Я упростил компонент, чтобы проиллюстрировать, что имеет решающее значение, и отладил его с помощью браузера devools. щелчок заканчивается в функции noop() {} react-dom.development.js. Любая идея, почему это?   -  person Odif Yltsaeb    schedule 11.02.2021
comment
Просто сделайте воспроизводимый пример в codeandbox, никто не догадается, как NavbarToggler реализовано   -  person Dennis Vash    schedule 11.02.2021
comment
Неа. Уже разобрался. Очевидно, слишком сложная механика замены, которую я использовал, каким-то образом испортила распространение событий. Я упростил это тоже, и теперь все работает нормально.   -  person Odif Yltsaeb    schedule 11.02.2021


Ответы (2)


Вы пробовали setState с обратным вызовом?

setIsOpen((prevState) => (
  !prevState
));
person k-wasilewski    schedule 10.02.2021

Не уверен, насколько полезен этот ответ для населения в целом. Нет onClick не работающих вопросов. Моды - если вы не видите, что здесь можно узнать, просто отметьте вопрос для удаления.

Итак, что здесь произошло, так это то, что у меня была эта механика замены реликвий в моем index.js, которая создала компонент. Я визуализировал компонент внутри элемента не в DOM:

        const temp = document.createElement('div');
        render(<NavBar element={wrap} />, temp);

А затем просмотрел его и заменил своего предшественника на чистом HTML компонентом реагирования. Я выбрал это сложное решение, потому что изначально я просто пытался повторно использовать некоторые компоненты. Позже я изменил эту логику, но не стал возвращаться к простому использованию render(<NavBar/>, wrap);, что избавило бы меня от всех проблем с написанием этого вопроса.

Так что моя собственная сложность, которую я не уменьшил вовремя, создала еще больше накладных расходов и потраченного времени. Так что да - избегайте сложности. Это урок здесь.

person Odif Yltsaeb    schedule 11.02.2021