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
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
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 auseEffect
hook with a dependency array containing[searchTerm]
. This means that the effect will run wheneversearchTerm
changes. When you click on a<Link>
in theMovieBlock.js
component, it navigates to a different page, causing theHome
component to unmount and then remount when the new page loads. This unmounting and remounting causes theuseEffect
cleanup function to run before the component is unmounted.Here’s what happens during the process:
searchTerm
state, triggering theuseEffect
with a 2-second delay.<Link>
, which triggers the navigation to a different page.Home
component unmounts since you are moving to a new page, and theuseEffect
cleanup function is called, which clears the timeout usingclearTimeout(useDelayFuctionRef.current);
and logs "cleaned".Home
component is re-rendered, but this time with a new state and props.useEffect
with the 2-second delay is set up again, and the process repeats for any further changes tosearchTerm
.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 thecomponentDidMount
lifecycle method in class components.Here’s the updated
useEffect
:By including
inputChanged
as a dependency, theuseEffect
will also run wheninputChanged
changes, but since it is a state that is managed within the component, it won’t be affected by the unmounting behavior during navigation.