#reactjs #react-router
#reactjs #react-router
Вопрос:
Кто-то с опытом работы с React-Router, вероятно, может ответить на этот вопрос. У меня есть приложение с целевой страницей, выпадающим меню на этой целевой странице и кнопкой «зарегистрироваться» <Link>
, которая ведет на простую страницу с формой входа.
Выпадающее меню использует систему react ref для размещения ссылки в выпадающем меню. Существует прослушиватель событий щелчка, который ссылается на эту ссылку, чтобы состояние выпадающего списка не переключалось при нажатии на что-либо внутри этой ссылки. И для этого прослушивателя событий click есть функция очистки, чтобы при закрытии меню прослушиватель событий больше не присутствовал.
Происходит то, что если открыто выпадающее меню, и вы нажимаете на <Link>
страницу входа в систему, оно создает нулевую ссылку в выпадающем меню из прослушивателя событий щелчка, хотя я пытаюсь полностью размонтировать эти компоненты и смонтировать другой с помощью react-router.
Мне неясно, должен ли я преобразовывать этот LandingMenu
компонент в class component, чтобы я мог использовать componentDidUnmount
для запуска функции очистки, или я неправильно использую react router, или есть другой «правильный» метод для решения этой проблемы, о котором я не знаю. Вот код.
App.js
import React, { Component } from "react";
import { BrowserRouter, Route, Switch } from "react-router-dom";
import "../styles/index.css";
import Landing from "./landing/Landing";
import Login from "./login/Login";
class App extends Component {
render() {
return (
<div>
<BrowserRouter>
<Switch>
<Route path="/" exact component={Landing} />
<Route path="/login" exact component={Login} />
</Switch>
</BrowserRouter>
</div>
);
}
}
export default App;
Кнопка входа в систему
import React from "react";
import { Link } from "react-router-dom";
import Button from "../common/Button";
import ChevronRight from "../icons/ChevronRight";
const LandingAuthentication = () => {
return (
<div className="login-buttons-wrapper">
<Link to="/login">
<Button Text="Sign in" Style="button-primary" Icon={<ChevronRight />} />
</Link>
</div>
);
};
export default LandingAuthentication;
Меню посадки
import React, { useState, useEffect, useRef } from "react";
import "../../styles/landing-menu.css";
const LandingMenu = ({ Title, Icon, children }) => {
// visibility toggle, default closed
const [open, setOpen] = useState(false);
// set menu ref to prevent double click event
const menuRef = useRef();
// close menu if clicked anywhere outside of menu
// on initial render, add click event listener
useEffect(() => {
const onBodyClick = (event) => {
// check if element clicked is inside of menu
// if so no action is required from this event listener so exit
if (menuRef.current.contains(event.target)) {
return;
}
// else close the menu
setOpen(false);
};
// add event listener and cleanup only if menu is open
if (open === true) {
document.body.addEventListener("click", onBodyClick);
// CLEANUP
// remove event listener
return () => {
document.body.removeEventListener("click", onBodyClick);
};
}
}, [open]);
// on click toggle state
return (
<nav className="landing-menu" ref={menuRef}>
<div
className="landing-menu-title-wrapper"
onClick={() => {
setOpen(!open);
}}
>
<h3 className="landing-menu-title">{Title}</h3>
<div className="landing-menu-title-icon">{Icon}</div>
</div>
<ul className={`dropdown ${open ? "visible" : "hidden"}`}>{children}</ul>
</nav>
);
};
export default LandingMenu;
Ответ №1:
Ошибка оказалась вызвана обновлением способа обработки ссылок React в React 17. Решение состоит в том, чтобы обновить if
инструкцию из:
if (menuRef.current.contains(event.target)) {
Для
if (menuRef.current amp;amp; menuRef.current.contains(event.target)) {