【问题标题】:document.querySelector() always return null when clicking on React Router Link the first time but will return correctly afterdocument.querySelector() 第一次点击 React Router Link 时总是返回 null 但之后会正确返回
【发布时间】:2021-01-01 23:47:19
【问题描述】:

我遇到了 React-Router 和 querySelector 的问题。

我有一个 Navbar 组件,其中包含所有用于导航的 CustomLink 组件和一个线动画,它监听这些组件并根据当前活动组件显示动画。

// Navbar.tsx

import React, { useCallback, useEffect, useState, useRef } from "react";
import { Link, useLocation } from "react-router-dom";

import CustomLink from "./Link";

const Layout: React.FC = ({ children }) => {
  const location = useLocation();
  const navbarRef = useRef<HTMLDivElement>(null);
  const [pos, setPos] = useState({ left: 0, width: 0 });

  const handleActiveLine = useCallback((): void => {
    if (navbarRef && navbarRef.current) {
      const activeNavbarLink = navbarRef.current.querySelector<HTMLElement>(
        ".tdp-navbar__item.active"
      );

      console.log(activeNavbarLink);

      if (activeNavbarLink) {
        setPos({
          left: activeNavbarLink.offsetLeft,
          width: activeNavbarLink.offsetWidth,
        });
      }
    }
  }, []);

  useEffect(() => {
    handleActiveLine();
  }, [location]);

  return (
    <>
      <div className="tdp-navbar-content shadow">
        <div ref={navbarRef} className="tdp-navbar">
          <div className="tdp-navbar__left">
            <p>Todo+</p>
            <CustomLink to="/">About</CustomLink>
            <CustomLink to="/login">Login</CustomLink>
          </div>
          <div className="tdp-navbar__right">
            <button className="tdp-button tdp-button--primary tdp-button--border">
              <div className="tdp-button__content">
                <Link to="/register">Register</Link>
              </div>
            </button>
            <button className="tdp-button tdp-button--primary tdp-button--default">
              <div className="tdp-button__content">
                <Link to="/login">Login</Link>
              </div>
            </button>
          </div>
          <div
            className="tdp-navbar__line"
            style={{ left: pos.left, width: pos.width }}
          />
        </div>
      </div>
      <main className="page">{children}</main>
    </>
  );
};

export default Layout;
// CustomLink.tsx
import React, { useEffect, useState } from "react";
import { useLocation, useHistory } from "react-router-dom";

interface Props {
  to: string;
}

const CustomLink: React.FC<Props> = ({ to, children }) => {
  const location = useLocation();
  const history = useHistory();
  const [active, setActive] = useState(false);

  useEffect(() => {
    if (location.pathname === to) {
      setActive(true);
    } else {
      setActive(false);
    }
  }, [location, to]);

  return (
    // eslint-disable-next-line react/button-has-type
    <button
      className={`tdp-navbar__item ${active ? "active" : ""}`}
      onClick={(): void => {
        history.push(to);
      }}
    >
      {children}
    </button>
  );
};

export default CustomLink;

但它没有按我的意愿工作。所以我打开 Chrome Devtool 并调试,我意识到当我首先点击 CustomLink 时,Navbar 中的 querySelector() 将返回 null。但是如果我多次点击同一个CustomLink,它会正确返回,如下图所示:

Error from Chrome Console

如何从querySelector()第一次获得正确的回报?谢谢!

【问题讨论】:

    标签: reactjs dom react-router-dom selectors-api


    【解决方案1】:

    这是因为handleActiveLine会在setActive(true)CustomLink.tsx之前触发

    CustomLink.tsx中添加回调:

    const CustomLink: React.FC<Props> = ({ onActive }) => {
    
      useEffect(() => {
        if (active) {
          onActive();
        }
      }, [active]);
    
    }
    

    Navbar.tsx:

    const Layout: React.FC = ({ children }) => {
      
      function handleOnActive() {
         // do your query selector here
      }
    
      // add onActive={handleOnActive} to each CustomLink
      return <CustomLink onActive={handleOnActive} />
    }
    

    【讨论】:

    • 谢谢!奇迹般有效。我要标记这个答案
    猜你喜欢
    • 2017-10-12
    • 2012-05-02
    • 2014-09-25
    • 2020-10-22
    • 2018-12-24
    • 1970-01-01
    • 2019-05-01
    • 2018-09-24
    • 1970-01-01
    相关资源
    最近更新 更多