useEffect не обновляет состояние при изменении маршрута - PullRequest
2 голосов
/ 25 сентября 2019

Я ищу решение для регистрации изменения маршрута и применения новых state с использованием setState и useEffect.Приведенный ниже код не обновляет функции setState при изменении маршрута.

Например, я регистрирую pathname из / с location.pathname === '/' в пределах createContext, если pathname равно /, зарегистрирован setState из isHome trueоднако, если pathname равно /page-1 setState зарегистрировано false.

При перезагрузке браузера onMount state установлено правильно, однако при изменении маршрута с помощью Link этоне.Также обратите внимание, что я использую Gatsby и при этом импортирую { Link } from 'gatsby'

CreateContext.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 и зарегистрировал бы prevProps.location.pathname против props.location.pathname, однако, насколько я понимаю, это больше не требуется с помощью хука useEffect.

Ответы [ 3 ]

1 голос
/ 25 сентября 2019

Эффект, который вы хотите получить: «Когда меняют местоположение, обновите мое состояние», это будет переведено в useEffect код, подобный следующему:

  useEffect(() => {
    detectHome();
    return () => {
      detectHome();
    };
  }, [location]);
0 голосов
/ 25 сентября 2019

Я думаю, что если вы используете GlobalProvider в качестве корневого компонента, в этом случае он рендерится только один раз, если что-то не изменит состояния или подпорки.Итак, некоторые объяснения:

  useEffect(() => {
    detectHome();
    return () => {
      detectHome();
    };
  }, [state.isHome]);

Этот код выше, state обновляется только этим useEffect, поэтому он обновляет состояние только один раз после первого рендеринга, а detectHome внутри returnuseEffect выполняется только тогда, когда происходит другое обновление или 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.

0 голосов
/ 25 сентября 2019

Если вы используете реагирующий маршрутизатор, вы можете подписаться на событие изменения местоположения в вашем useEffect:

import {browserHistory} from 'react-router';

...
useEffect(() => {
  return browserHistory.listen(detectHome);
}, []);
...

Это позволит подписать вашу функцию detectHome на изменение местоположения при монтировании и отписаться от нее при отключении.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...