为什么useEffect不会在window.location.pathname
更改时运行?我loc
只登录一次。
在没有任何附加库的情况下,当路径名更改时如何运行useEffect?
useEffect(() => {
const loc = window.location.pathname
console.log({ loc })
}, [window.location.pathname])
为什么useEffect不会在window.location.pathname
更改时运行?我loc
只登录一次。
在没有任何附加库的情况下,当路径名更改时如何运行useEffect?
useEffect(() => {
const loc = window.location.pathname
console.log({ loc })
}, [window.location.pathname])
创建一个钩子,例如:
const useReactPath = () => {
const [path, setPath] = React.useState(window.location.pathname);
const listenToPopstate = () => {
const winPath = window.location.pathname;
setPath(winPath);
};
React.useEffect(() => {
window.addEventListener("popstate", listenToPopstate);
return () => {
window.removeEventListener("popstate", listenToPopstate);
};
}, []);
return path;
};
然后在您的组件中像这样使用它:
const path = useReactPath();
React.useEffect(() => {
// do something when path changes ...
}, [path]);
当然,您必须在顶级组件中执行此操作。
我改编了 Rafael Mora 的答案,使其适用于整个位置对象,并使用该useIsMounted
方法在 Next.js 应用程序的前端工作,并添加了typescript类型。
hooks/useWindowLocation.ts
import useIsMounted from './useIsMounted'
import { useEffect, useState } from 'react'
const useWindowLocation = (): Location|void => {
const isMounted = useIsMounted()
const [location, setLocation] = useState<Location|void>(isMounted ? window.location : undefined)
useEffect(() => {
if (!isMounted) return
const setWindowLocation = () => {
setLocation(window.location)
}
if (!location) {
setWindowLocation()
}
window.addEventListener('popstate', setWindowLocation)
return () => {
window.removeEventListener('popstate', setWindowLocation)
}
}, [isMounted, location])
return location
}
export default useWindowLocation
hooks/useIsMounted.ts
import { useState, useEffect } from 'react'
const useIsMounted = (): boolean => {
const [isMounted, setIsMounted] = useState(false)
useEffect(() => {
setIsMounted(() => true)
}, [])
return isMounted
}
export default useIsMounted
useEffect
每次渲染组件时都会进行评估。要订阅对 的更改location.pathname
,您需要向 的更新状态window
的'popstate'
事件添加一个侦听器,该事件告诉组件树重新渲染。
Rafel Mora 的回答使用实现了一个钩子setState
,这将导致组件重新渲染。然后,您可以使用从钩子返回的状态值useEffect
代替window.location.pathname
.
相关 - 这是 ESLint 警告,如果您使用,您会看到eslint-plugin-react-hooks
:
像“window.location.pathname”这样的外部范围值不是有效的依赖项,因为改变它们不会重新渲染组件
如果你愿意使用库,React Router 提供了一个useLocation钩子。
我不知道为什么,但对我来说,添加'popstate'
从未奏效的听众并且我能够useEffect
在更改时进行window.location.pathname
更改,类似于 karolis 在他们的原始问题中所做的没有问题。这就是我所做的:
let path = window.location.pathname;
/* potentially changes navbar on page change */
useEffect(() => {
if (window.location.pathname === "/") {
setScrollNav(false);
} else {
setScrollNav(true);
}
}, [path]);
这似乎解决了我遇到的问题,但与其他人相比,我的经历似乎非常不同,所以我很想知道您的想法。