skip to Main Content

Home.js

export default function Home({ movies }) {
  const [searchTerm, setSearchTerm] = useState("");
  const [inputChanged, setInputChanged] = useState(false);
  const [loading, setLoading] = useState(false);
  const useDelayFuctionRef = useRef(null);
  const router = useRouter();
  const client = {id:'',pass:''}
  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]);

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

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

MovieBlock.js

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

When I click on any <Link> 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 ?

2

Answers


  1. Chosen as BEST ANSWER

    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


  2. 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 <Link> 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 <Link>, 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(() => {
      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]); // 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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search