useEffect在输入未更改时仍调用函数。

huangapple go评论55阅读模式
英文:

useEffect calling function even if input is not changed

问题

When you click on any <Link> in MovieBlock.js, it triggers a redirect after a 2-second delay. However, the return function from the useEffect in the Home.js component logs "cleaned" after redirecting to the desired page. This behavior is related to how the cleanup function works in React.

In React, when you define a useEffect with a cleanup function, the cleanup function is executed when the component is unmounted or when the dependencies specified in the useEffect array change. In your case, you have the following useEffect in Home.js:

useEffect(() => {
  // ...
  return () => {
    clearTimeout(useDelayFuctionRef.current);
    console.log("cleaned");
  };
}, [searchTerm]);

The cleanup function is executed when searchTerm changes. However, when you click on a <Link> in MovieBlock.js, it triggers a redirection but doesn't cause the searchTerm to change. Therefore, the cleanup function is not executed in this case.

If you want to perform cleanup when you navigate away from the Home component by clicking on a <Link>, you can listen to route changes using useEffect with router from next/router:

import { useRouter } from "next/router";

// ...

export default function Home({ movies }) {
  const router = useRouter();

  // ...

  useEffect(() => {
    const handleRouteChange = () => {
      // Perform cleanup here
      clearTimeout(useDelayFuctionRef.current);
      console.log("cleaned");
    };

    router.events.on("routeChangeStart", handleRouteChange);

    return () => {
      router.events.off("routeChangeStart", handleRouteChange);
    };
  }, []);

  // ...
}

This code sets up an event listener for route changes using router.events.on and removes the listener when the component unmounts using router.events.off. This way, you can perform cleanup when the user navigates away from the Home component, including when they click on a <Link>.

英文:

Home.js

export default function Home({ movies }) {
  const [searchTerm, setSearchTerm] = useState(&quot;&quot;);
  const [inputChanged, setInputChanged] = useState(false);
  const [loading, setLoading] = useState(false);
  const useDelayFuctionRef = useRef(null);
  const router = useRouter();
  const client = {id:&#39;&#39;,pass:&#39;&#39;}
  useEffect(() =&gt; {
    const searchQuery = () =&gt; {
      router.push(`${router.pathname}/?search=${searchTerm}`);
    };
    if (inputChanged) {
      useDelayFuctionRef.current = setTimeout(() =&gt; {
        searchQuery();
        setInputChanged(false);
        setLoading(false);
      }, 2000);
    }
    return () =&gt; {
      clearTimeout(useDelayFuctionRef.current);
      console.log(&quot;cleaned&quot;);
    };
  }, [searchTerm]);

  return (
    &lt;div&gt;
      &lt;div&gt;
          &lt;input
            type=&quot;text&quot;
            onChange={(e) =&gt; {
              setSearchTerm(e.target.value);
              setInputChanged(true);
              setLoading(true);
            }}
          /&gt;
      &lt;/div&gt;
      &lt;div&gt;
        {movies.map((movie) =&gt; {
          return (
            &lt;MovieBlock key={movie._id} movie={movie} client={client}/&gt;
          );
        })}
      &lt;/div&gt;
    &lt;/div&gt;
  );
}

export async function getServerSideProps({ query }) {
  const movies = await fetch(query.string);
  return {
    props: {
      movies,
    },
  };
}

MovieBlock.js

export default function MovieBlock({ movie, client }) {
  return (
    &lt;div&gt;
      &lt;Link
        key={movie._id}
        href={`/movie/${movie.slug}`}
      &gt;
        &lt;img src={movie.vertical_image} /&gt;
      &lt;/Link&gt;
      &lt;div&gt;
        &lt;span&gt;
          {movie.genre.map((genre) =&gt; &lt;Link key={genre._id} href={`/genre/${genre.slug}`}&gt;{genre.title}&lt;/Link&gt;
          }
        &lt;/span&gt;
        &lt;span&gt;{movie.title}&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  );
}

When I click on any &lt;Link&gt; in MovieBlock.js it waits for 2 seconds, and then redirects to the page link that was clicked, the return function from useEffect logs "cleaned" after redirecting to the desired page, why is this happening on redirects other than input:onChange although having condition ? Is there something to do with cleanup function ?

答案1

得分: 1

你正在经历的与useEffect清理函数相关的行为与React处理组件卸载和更新的方式有关。

在你的Home组件中,你有一个带有依赖数组[searchTerm]useEffect钩子。这意味着当searchTerm更改时,效果将运行。当你在MovieBlock.js组件中单击一个&lt;Link&gt;时,它会导航到不同的页面,导致Home组件卸载,然后在加载新页面时重新挂载。这种卸载和重新挂载会导致useEffect清理函数在组件卸载之前运行。

以下是该过程中发生的情况:

  1. 你在输入框中输入文字,这会更改searchTerm状态,触发带有2秒延迟的useEffect
  2. 在2秒延迟结束之前,你单击了一个&lt;Link&gt;,触发了导航到不同页面的操作。
  3. 当前的Home组件卸载,因为你正在跳转到一个新页面,并且调用了useEffect清理函数,它使用clearTimeout(useDelayFuctionRef.current);清除了超时并记录了“cleaned”。
  4. 新页面加载,并且Home组件重新渲染,但这次使用了新的状态和属性。
  5. 由于组件被重新渲染,具有2秒延迟的useEffect再次设置,对于searchTerm的任何进一步更改,该过程将重复。

为了避免这种行为,你可以在useEffect钩子中添加一个依赖项,以便它仅在组件首次挂载时运行。通过提供一个空的依赖数组([]),效果将仅运行一次,相当于类组件中的componentDidMount生命周期方法。

以下是更新后的useEffect

useEffect(() => {
  const searchQuery = () => {
    router.push(`${router.pathname}/?search=${searchTerm}`);
  };
  if (inputChanged) {
    useDelayFuctionRef.current = setTimeout(() => {
      searchQuery();
      setInputChanged(false);
      setLoading(false);
    }, 2000);
  }
  return () => {
    clearTimeout(useDelayFuctionRef.current);
    console.log("cleaned");
  };
}, [searchTerm, inputChanged]); // 将inputChanged添加为依赖项

通过将inputChanged包括为依赖项,useEffect也会在inputChanged更改时运行,但由于它是在组件内管理的状态,不会受到导航期间的卸载行为的影响。

英文:

The behavior you are experiencing with the useEffect cleanup function is related to how React handles component unmounting and updating.

In your Home component, you have a useEffect hook with a dependency array containing [searchTerm]. This means that the effect will run whenever searchTerm changes. When you click on a &lt;Link&gt; in the MovieBlock.js component, it navigates to a different page, causing the Home component to unmount and then remount when the new page loads. This unmounting and remounting causes the useEffect cleanup function to run before the component is unmounted.

Here's what happens during the process:

  1. You type in the input, which changes the searchTerm state, triggering the useEffect with a 2-second delay.
  2. Before the 2-second delay elapses, you click on a &lt;Link&gt;, which triggers the navigation to a different page.
  3. The current Home component unmounts since you are moving to a new page, and the useEffect cleanup function is called, which clears the timeout using clearTimeout(useDelayFuctionRef.current); and logs "cleaned".
  4. The new page loads, and the Home component is re-rendered, but this time with a new state and props.
  5. Since the component is re-rendered, the useEffect with the 2-second delay is set up again, and the process repeats for any further changes to searchTerm.

To avoid this behavior, you can add a dependency to your useEffect hook, so it only runs when the component is initially mounted. By providing an empty dependency array ([]), the effect will only run once, equivalent to the componentDidMount lifecycle method in class components.

Here's the updated useEffect:

useEffect(() =&gt; {
  const searchQuery = () =&gt; {
    router.push(`${router.pathname}/?search=${searchTerm}`);
  };
  if (inputChanged) {
    useDelayFuctionRef.current = setTimeout(() =&gt; {
      searchQuery();
      setInputChanged(false);
      setLoading(false);
    }, 2000);
  }
  return () =&gt; {
    clearTimeout(useDelayFuctionRef.current);
    console.log(&quot;cleaned&quot;);
  };
}, [searchTerm, inputChanged]); // Add inputChanged as a dependency

By including inputChanged as a dependency, the useEffect will also run when inputChanged changes, but since it is a state that is managed within the component, it won't be affected by the unmounting behavior during navigation.

答案2

得分: 0

我太蠢了,不知道ReactDevTools扩展程序已经安装在我的浏览器中 🤦🏻‍♂️(在StackOverflow上查找后找到了解决方案),尝试在不同的帐户选项卡上运行,它完美运行了。

英文:

I was too dumb to know that ReactDevTools extension was installed in my browser 🤦🏻‍♂️(got the solution on stackoverflow after some looking), tried running on differect account tab and it worked perfectly

huangapple
  • 本文由 发表于 2023年7月28日 00:18:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/76781677.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定