问题描述
我遇到了 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
时,来自 querySelector()
的 Navbar
将返回 null。但是如果我多次点击同一个 CustomLink
,它会正确返回,如下图所示:
如何从第一次开始从 querySelector()
获得正确的回报?谢谢!
解决方法
这是因为 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} />
}