如果 URL 哈希值发生变化,如何激活效果?

How do I activate an effect if the URLs hash changes?

提问人:Dave 提问时间:11/18/2023 最后编辑:jonrsharpeDave 更新时间:11/18/2023 访问量:44

问:

我正在使用 Ionic 7 和 React 18。如果 URL 的哈希部分发生变化,我想在我的容器中激活一个不同的组件。我试过这样做:

const MyContainer: React.FC<ContainerProps> = () => {
    ...

  useEffect(() => {
    // Set step based on the hash in the URL
    const hash = window.location.hash.substring(1); // Remove the '#' from the hash
    switch (hash) {
        ...
      case 'message':
        dispatch(setStep(StepsEnum.Message));
        break;
    }
  }, []);

    ...
        {step === StepsEnum.Name && <MyFirstComponent />}
        {step === StepsEnum.Address && <MySecondComponent  />}
        {step === StepsEnum.Message && <MyThirdComponent />}
      </IonContent>
    </IonPage>
  )
}

export default MyContainer

不幸的是,当我在浏览器中输入不同的哈希值时,什么也没发生(至少,我没有看到我的useEffect被调用)。是否可以根据 URL 的哈希值激活不同的组件?

reactjs 离子框架 react-hooks

评论

0赞 jonrsharpe 11/18/2023
我不明白你为什么会期望这会导致变化。空依赖项列表意味着它只在初始渲染时被调用一次

答:

1赞 Ori Drori 11/18/2023 #1

除非你使用路由器,如 React Router,它提供了跟踪 URL 更改的钩子,否则你需要显式侦听事件。hashchange

示例(单击链接):

const { useState, useEffect } = React;

const MyContainer = () => {
  const [hash, setHash] = useState();

  useEffect(() => {
    const handleUrlChange = () => {
      setHash(window.location.hash.substring(1));
    };
    
    window.addEventListener('hashchange', handleUrlChange);
    
    return () => {
      window.removeEventListener('hashchange', handleUrlChange);
    };
  }, []);
  
  return (
    <div>
      <a href="#1">1</a>
      <a href="#2">2</a>
      <a href="#3">3</a>
      <a href="#4">4</a>
      {hash}
    </div>
  );
};

ReactDOM
  .createRoot(root)
  .render(<MyContainer />);
a {
  margin: 0.5em;
}
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>

<div id="root"></div>

您可以将哈希跟踪代码提取到钩子(预期):useHash

const { useState, useEffect } = React;

const useHash = () => {
  const [hash, setHash] = useState();

  useEffect(() => {
    const handleUrlChange = () => {
      setHash(window.location.hash.substring(1));
    };
    
    window.addEventListener('hashchange', handleUrlChange);
    
    return () => {
      window.removeEventListener('hashchange', handleUrlChange);
    };
  }, []);

  return hash;
};

const MyContainer = () => {
  const hash = useHash();
  
  return (
    <div>
      <a href="#1">1</a>
      <a href="#2">2</a>
      <a href="#3">3</a>
      <a href="#4">4</a>
      {hash}
    </div>
  );
};

ReactDOM
  .createRoot(root)
  .render(<MyContainer />);
a {
  margin: 0.5em;
}
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>

<div id="root"></div>

现在你可以用以下方式触发你的生产:useEffecthashuseHash

const MyContainer = () => {
  const hash = useHash();
  
  useEffect(() => {
    switch (hash) {
        ...
      case 'message':
        dispatch(setStep(StepsEnum.Message));
        break;
    }
  }, [hash]);

评论

0赞 Dave 11/20/2023
你提到“除非你使用react router......”我确实安装了“@ionic/react-router”(7.0.0),这是否允许我做一些与您上面详述的不同的事情?
0赞 Ori Drori 11/20/2023
是的。React Router 有一个钩子 - v5v6。我认为 ionic 仍然使用 React Router 5。useLocation
0赞 Dave 11/20/2023
总而言之,我会使用 useLocation 钩子来监听 URL 更改并等到检测到哈希更改?
0赞 Ori Drori 11/21/2023
并使用哈希作为 的依赖项。useEffect