useEffect 不会在路由更改时更新状态

IT技术 javascript reactjs react-hooks gatsby
2021-05-24 12:48:53

我正在寻找一种解决方案来注册路线更改并state使用setState应用新的useEffect下面的当前代码不会更新setState更改路线时的功能

例如,我注册pathname/location.pathname === '/'createContext,如果pathname/所述setStateisHome被登记true,但是如果pathname/page-1 setState被登记false

在浏览器重新加载,onMountstate使用正确设置,但在路线改变Link这个没有。另外,请注意,我正在使用 Gatsby 并在这样做时导入{ 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更改路线时如何更新状态以前,我会使用componentDidUpdateprevProps.location.pathname针对注册props.location.pathname,但是,我的理解是useEffect钩子不再需要这样做

3个回答

你想要的效果是“当位置改变时更新我的​​状态”,这在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]);

上面这段代码, thestate只被 this 更新useEffect,所以它只在第一次渲染后更新一次状态,并且detectHomereturn内部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>
  );
};

我认为 Gatsby 应该操纵历史记录,所以这会触发popstate浏览器,并且您可以检测到 url 的变化。