【问题标题】:React-Router Route is creating a null ref from unmounted functional componentReact-Router Route 正在从未安装的功能组件创建空 ref
【发布时间】: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


    【解决方案1】:

    该错误最终是由 React 处理 React 17 中引用的方式更新引起的。解决方案是从以下位置更新 if 语句:

    if (menuRef.current.contains(event.target)) {

    if (menuRef.current &amp;&amp; menuRef.current.contains(event.target)) {

    【讨论】:

      猜你喜欢
      • 2021-09-15
      • 1970-01-01
      • 2020-08-11
      • 1970-01-01
      • 1970-01-01
      • 2018-12-02
      • 1970-01-01
      • 1970-01-01
      • 2018-08-25
      相关资源
      最近更新 更多