2022-08-27 - A trick to useEffect conditionally
tl;dr: place useEffect in a separate component where it’s conditionally rendered
–
First, it’s no doubt that we can’t bypass the Rules of Hooks which includes Don't call Hooks inside conditions. But sometimes, I just want my useEffect to be run in a certain circumstance.
Say, I have a table representing my friends’ basic personal information. Each row displays Avatar, Phone Number, Gender, you name it. Of course, each of my friend has an ID with which I use to make a request to get the data.
It would look like this:
// FriendRow.jsx
const FriendRow = ({ id }) => {
useEffect(() => {
getFriendData(id)
}, [id])
return <div>{/* other components */}</div>
}
Yes, I know I can use a single request to get data of all friends. What I wanna point out here is that it’s an example of useEffect being called for every components of the list (a list of <FriendRow />). Now, I want to fetch since when we became friends for FEMALE people only, and display it in a cell named From. Only FEMALE.
My first, native, brainless thought was:
// FriendRow.jsx
const FriendRow = ({ id }) => {
useEffect(() => {
getFriendData(id)
}, [id])
if (friend.isFemale) {
useEffect(() => {
getFriendshipSinceWhen(id)
}, [id])
}
return <div>{/* other components */}</div>
}
It failed immediately. Instead, what I did in this case is to move the second useEffect into SinceWhenCell component. Like this:
// FriendRow.jsx
const FriendRow = ({ id }) => {
useEffect(() => {
getFriendData(id)
}, [id])
if (friend.isFemale) {
useEffect(() => {
getFriendshipSinceWhen(id)
}, [id])
}
return (
<div>
{/* other components */}
{friend.isFemale ? <SinceWhenCell id={id} /> : null}
</div>
)
}
// SinceWhenCell.jsx
const SinceWhenCell = ({ id }) => {
useEffect(() => {
getFriendshipSinceWhen(id)
}, [id])
return <div />
}
I already achieved my “conditional hook calling” request without compromising Rules of Hooks. Hooray!