简体   繁体   English

页面在 history.push() 后不重新渲染

[英]Page not rerendering after history.push()

I'm using React Router with my React dictionary project, and for some reason my page doesn't re-render after I run history.push() (using the useHistory hook from react-router).我在 React 字典项目中使用 React Router,由于某种原因,我的页面在运行history.push() (使用 react-router 的useHistory钩子history.push()后没有重新呈现。 I have a search bar, and I use this function to go to a new link.我有一个搜索栏,我使用此功能转到新链接。

const KeyPressHandler: KeyboardEventHandler<HTMLInputElement> = (event) => {
    const { value } = event.currentTarget;
    if ((event.code === "Enter" || event.code === "NumpadEnter") && value.length)
      history.push(`/dictionary/${value}`);
    };
  };

My App component looks like this:我的App组件如下所示:

const App = (): JSX.Element => {
  ...
  return (
    ...
      <Route path="/dictionary" component={DictionaryEntryPage} />
    ...
  );
};

This is what the DictionaryEntryPage component is:这是DictionaryEntryPage组件的内容:

const DictionaryEntryPage = (): JSX.Element => {
  const [wordData, setWordData] = useState<WordData[] | undefined | null>(undefined);
  // useRouteMatch is imported from react-router
  const match = useRouteMatch<{ requestedWord: string }>("/dictionary/:requestedWord");

  useEffect(() => {
    const { requestedWord } = match?.params ?? {};

    if (requestedWord) {
      (async () => {
        const data = await parseWordData(requestedWord);
        setWordData(data || null);
      })();
    } else setWordData(null);
  }, []);
  
  const wordDataEls = wordData ? wordData.map((data, i) => <Word {...data} key={i} />) : <Loading />;

  ...
}

Let me know what I should add to/remove from the question, and here 'sa demo link if someone want to see it.让我知道我应该从问题中添加/删除什么,如果有人想看,这里有一个演示链接。

I think you'll actually find that your component is re-rendering properly.我认为您实际上会发现您的组件正在正确地重新渲染。 The issue is with your useEffect , rather than an issue with rendering.问题在于您的useEffect ,而不是渲染问题。

In your useEffect , you have an empty dependencies array at the end [] .在您的useEffect[]末尾有一个空的依赖项数组。 By having an empty dependencies array, you are essentially telling React that nothing will ever change and cause this side effect to re run (which is not the case).通过拥有一个空的依赖项数组,您实际上是在告诉 React 什么都不会改变并导致这种副作用重新运行(事实并非如此)。 If that is truly your desire, and you only want the side effect to run when the component first mounts, you should remove the dependencies array altogether, which would cause your code to look like this:如果这确实是您的愿望,并且您只想在组件第一次挂载时运行副作用,则应该完全删除依赖项数组,这将导致您的代码如下所示:

useEffect(() => {
    const { requestedWord } = match?.params ?? {};
    console.log('ran effect');
    if (requestedWord) {
      (async () => {
        const data = await parseWordData(requestedWord);
        setWordData(data || null);
      })();
    } else setWordData(null);
  });

What you really want, though, is to actually cause that effect to re-run every time the search term changes.但是,您真正想要的是在每次搜索词更改时重新运行该效果。 Leaving everything else about your useEffect the same, that'd give you this:保留有关useEffect的所有其他内容,这将为您提供:

useEffect(() => {
    const { requestedWord } = match?.params ?? {};
    console.log('ran effect');
    if (requestedWord) {
      (async () => {
        const data = await parseWordData(requestedWord);
        setWordData(data || null);
      })();
    } else setWordData(null);
  }, [
      match
  ]);

The above still has some problems, though.不过上面还是有一些问题。 Namely, match is an object, which means it's a reference type.也就是说, match是一个对象,这意味着它是一个引用类型。 When deciding whether or not to re-run a side effect, React only does shallow comparisons rather than deeply inspecting reference types to see if they are equal (check out this article for a better explanation of reference vs value types).在决定是否重新运行副作用时,React 只进行浅层比较,而不是深入检查引用类型以查看它们是否相等(查看本文以更好地解释引用与值类型)。 Basically, if you leave the useEffect like that, you'll be running the effect too much and probably get yourself lots of rate limit errors from your API.基本上,如果你像这样离开useEffect ,你将运行过多的效果,并且可能会从你的 API 中得到很多速率限制错误。

So, the final example of what you want is this:所以,你想要的最后一个例子是:

const DictionaryEntryPage = (): JSX.Element => {
  const [wordData, setWordData] = useState<WordData[] | undefined | null>(undefined);
  const match = useRouteMatch<{ requestedWord: string }>("/dictionary/:requestedWord");
  const { requestedWord } = match?.params ?? {};

  useEffect(() => {
    console.log('ran effect');
    if (requestedWord) {
      (async () => {
        const data = await parseWordData(requestedWord);
        setWordData(data || null);
      })();
    } else setWordData(null);
  }, [
    requestedWord
  ]);

  //...
}

Now you're extracting the requestedWord (which is a string and therefore a value type) at render and your useEffect simply has a dependency on that string.现在您在渲染时提取所requestedWord (它是一个字符串,因此是一个值类型),并且您的useEffect只是依赖于该字符串。 Now your effect will be making the correct number of requests to the API and it won't have stale data about the requested word.现在,您的效果将向 API 发出正确数量的请求,并且不会有关于所请求单词的陈旧数据。

As an aside, I'd strongly recommend that you install the eslint-plugin-react-hooks and add it to your .eslintrc.json and extend from it.顺便说一句,我强烈建议您安装eslint-plugin-react-hooks并将其添加到您的 .eslintrc.json 并从中扩展。 It has a rule called exhaustive-deps which would have caught this and warned you ahead of time.它有一个叫做exhaustive-deps的规则,它会发现这个并提前警告你。

Additional reading about exhaustive dependencies: https://reactjs.org/docs/hooks-faq.html#why-am-i-seeing-stale-props-or-state-inside-my-function关于详尽依赖的附加阅读: https : //reactjs.org/docs/hooks-faq.html#why-am-i-seeing-stale-props-or-state-inside-my-function

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 登录 function 后 history.push 不起作用 - history.push is not working after login function /url 页面中的 Javascript 功能在使用 history.push(/url) onlick 后不起作用 - Javascript function in /url page not working after using history.push(/url) onlick 当用户在 history.push() 之后按下“返回”按钮时,我们可以刷新页面吗 - Can we refresh a page when a user presses "go back" button after history.push() history.push 的问题 - Issue with history.push 更新状态 (useState) 并导航 (history.push) 到另一个页面……正确吗? - Update state (useState) and navigate (history.push) to another page… is it correct? history.push 添加新记录时重新加载页面很慢 - history.push is slow to reload page when adding a new record 来自 Action Creator 的 history.push() 将更改 URL 但不会导航到页面 - history.push() from Action Creator will Change URL but will Not Navigate to Page React-router - 通过 history.push() 导航刷新页面 - React-router - navigating through history.push() refreshes the page 在 React Router Dom 中使用 history.push 登录/注销的空白页面 - Blank page on login/logout with history.push in React Router Dom React - 调用history.push后错误的组件渲染 - React - Wrong component rendering after calling history.push
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM