de facto, nothing I'm aware of has changed
The thing that's changed is that you're no longer calling your state setter (isCurrentFarmerLikedFlagToggle) at the top level of your function component. You can't call state setters at the top level of a function component (even if you're setting the same value, but in your case, you may not be, it could have changed between renders), because the function component is called during the render phase, which must be pure (other than scheduling side effects to happen later).
But there's a more fundamental issue: there's no need for that flag to be in state at all. Copying stateful information the component receives (as props, as context, etc.) into component state is, in general, an antipattern (more here). In your example, you don't need isCurrentFarmerLikedFlag to be a state member; it's value is derived purely from information your component is already being provided: authCtx.currentLoggedUserId and usersAndItemsCtx.likedProfilesId:
let authCtx = useContext(AuthContext);
let usersAndItemsCtx = useContext(usersAndProductsContext);
let current_logged_user = usersAndItemsCtx.usersVal.find(
(user) => user.id === authCtx.currentLoggedUserId
);
let isCurrentFarmerLikedFlag = current_logged_user.likedProfilesId.find((id) => id === props.id) ? true : false;
// ^^^^^^^^^^^^^^^^^^^^^^^^
If you thought the work involved in determining that value was too much to do on every render, you can memoize the value via useMemo (or any of various other memoization helpers):
let authCtx = useContext(AuthContext);
let usersAndItemsCtx = useContext(usersAndProductsContext);
let current_logged_user = useMemo(
() => usersAndItemsCtx.usersVal.find((user) => user.id === authCtx.currentLoggedUserId),
[authCtx.currentLoggedUserId, usersAndItemsCtx.usersVal]
);
let isCurrentFarmerLikedFlag = useMemo(
() => (current_logged_user.likedProfilesId.find((id) => id === props.id) ? true : false),
[current_logged_user.likedProfilesId]
);
(More notes on that code below.)
The callback calculates the value, and the dependency array tells useMemo when it should call the callback again because something changed. Anything you use directly in the calculation should be listed in the dependency array. (But note that there's no need to list the container something comes from; we have authCtx.currentLoggeduserId in the first dependency array above, for instance, not both authCtx and authCtx.currentLoggeduserId. We don't care if authCtx changed but authCtx.currentLoggeduserId didn't, because we don't use authCtx except for its authCtx.currentLoggeduserId value.)
A few side notes:
- While you can (of course) use any naming convention you like in your own code, I urge you to follow standard practice when writing code you'll share with others. The standard practice for naming state setters is that they have the name of the state variable (with its first letter capitalized) prefixed with the word
set. So if the flag is isCurrentFarmerLikedFlag, the setter should be setIsCurrentFarmerLikedFlag. (Separately, isCurrentFarmerLikedFlagToggle is a particularly problematic name because it doesn't toggle the value, it accepts a new value to set [which may or may not be toggled.])
- This code:
current_logged_user.likedProfilesId.find((id) => id === props.id) ? true : false
can more succinctly and idiomatically be written (but keep reading):
current_logged_user.likedProfilesId.some((id) => id === props.id)
Any time you want to just know if an array has an element that matches the predicate function you pass in, you can use some rather than find. But, since you don't actually need a predicate function at all (you're just checking for the direct existence of a value), we can go even further and use includes:
current_logged_user.likedProfilesId.includes(props.id)
- All of the
let declarations in that code could be const instead, and I'd urge you to use const because directly modifying their values (isCurrentFarmerLikedFlag = newValue) won't work and is misleading.
Taking all of that into account:
const authCtx = useContext(AuthContext);
const usersAndItemsCtx = useContext(usersAndProductsContext);
const current_logged_user = useMemo(
() => usersAndItemsCtx.usersVal.find((user) => user.id === authCtx.currentLoggedUserId),
[authCtx.currentLoggedUserId, usersAndItemsCtx.usersVal]
);
const isCurrentFarmerLikedFlag = useMemo(
() => current_logged_user.likedProfilesId.includes(props.id),
[current_logged_user.likedProfilesId]
);