我正在寻找一种解决方案来注册路由更改并使用setState
和useEffect
应用新state
。下面的当前代码不会在更改路由时更新setState
的功能。
例如,我在createContext
内向location.pathname === '/'
注册/
的pathname
,如果pathname
/
isHome
的setState
true
注册,但是如果pathname
/page-1
setState
注册false
。
在浏览器重新加载时,onMount
正确设置了state
,但是在使用Link
更改路由时,这不会。另外,请注意,我正在使用盖茨比,并在这样做时导入{ Link } from 'gatsby'
创建上下文.js
export const GlobalProvider = ({ children, location }) => {
const prevScrollY = useRef(0);
const [state, setState] = useState({
isHome: location.pathname === '/',
// other states
});
const detectHome = () => {
const homePath = location.pathname === '/';
if (!homePath) {
setState(prevState => ({
...prevState,
isHome: false
}));
}
if (homePath) {
setState(prevState => ({
...prevState,
isHome: true
}));
}
};
useEffect(() => {
detectHome();
return () => {
detectHome();
};
}, [state.isHome]);
return (
<GlobalConsumer.Provider
value={{
dataContext: state,
}}
>
{children}
</GlobalConsumer.Provider>
);
};
如果我console.log(state.isHome)
pathname
/
我得到true
,我得到的任何其他路径名false
,但是,如果我更改路由,当前isHome
状态将保持先前状态,直到我滚动并useEffect
适用。
注册isHome
状态的目的是更改每页的 CSS。
更改路线时如何使用useEffect
更新状态。以前,我会用componentDidUpdate
来做到这一点,并针对props.location.pathname
注册prevProps.location.pathname
,但是,我的理解是,对于useEffect
钩子,这不再是必需的。
你想要的效果是"当位置更改然后更新我的状态时",这是useEffect
代码翻译的,如下所示:
useEffect(() => {
detectHome();
return () => {
detectHome();
};
}, [location]);
如果您使用的是 react-router,您可以在 useEffect 中订阅位置更改事件:
import {browserHistory} from 'react-router';
...
useEffect(() => {
return browserHistory.listen(detectHome);
}, []);
...
这将订阅您的detectHome
函数,以便在装载时更改位置,并在卸载时取消订阅。
我认为如果您使用GlobalProvider
作为根组件,在这种情况下,它只会渲染一次,除非某些内容更改了状态或 props。所以一些解释:
useEffect(() => {
detectHome();
return () => {
detectHome();
};
}, [state.isHome]);
上面的这段代码,state
只由这个useEffect
更新,所以它只在第一次渲染后更新一次状态,而 return 的detectHome
的useEffect
只有在发生其他更新或state.isHome
与第一次不同时才执行。这个解释有点令人困惑,但就是这样。
但是对于解决方案,请使用窗口的"popstate"事件:
export const GlobalProvider = ({ children, location }) => {
const prevScrollY = useRef(0);
const [state, setState] = useState({
isHome: location.pathname === '/',
// other states
});
const detectHome = () => {
const homePath = location.pathname === '/';
if (!homePath) {
setState(prevState => ({
...prevState,
isHome: false
}));
}
if (homePath) {
setState(prevState => ({
...prevState,
isHome: true
}));
}
};
useEffect(() => {
window.addEventListener('popstate', detectHome)
return () => {
window.removeEventListener('popstate', detectHome)
};
}, [state.isHome]);
return (
<GlobalConsumer.Provider
value={{
dataContext: state,
}}
>
{children}
</GlobalConsumer.Provider>
);
};
我认为盖茨比应该操纵历史记录,所以这将触发浏览器popstate
,您可以检测到 url 的更改。