【发布时间】:2021-02-21 09:07:10
【问题描述】:
有 React-Router 经验的人可能会回答这个问题。我有一个带有登录页面的应用程序,该登录页面上有一个下拉菜单和一个“注册”按钮,<Link> 指向一个带有登录表单的简单页面。
下拉菜单使用 react ref 系统在下拉菜单上放置一个 ref。有一个单击事件侦听器引用此 ref,因此当单击该 ref 内的任何内容时,不会切换下拉列表的状态。并且该点击事件监听器有一个清理功能,这样当菜单关闭时,事件监听器就不再存在了。
发生的情况是,如果下拉菜单打开,并且您单击<Link> 到登录页面,它会在单击事件侦听器的下拉菜单上创建一个空引用,即使我正在尝试完全卸载这些组件并使用 react-router 安装另一个组件。
我不清楚我是否应该将此LandingMenu 组件转换为类组件以便我可以使用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;
【问题讨论】:
标签: reactjs react-router