reactjsreact-hooksreact-custom-hooks

How can I pass a dependency to a custom hook to and behave like a useEffect?


How to trigger the useEffect inside useRedirect custom hook again if the given deps (or dependencies) changes?

Code:

const OnboardingLayout = () => {
    const { user } = useUserContext()

    useRedirect("/c", () => {
        if (user) {
            Object.values(user.onboarding).every(e => e)
        }
    }, [user])

    return (
        <Outlet />
    )
}
export const useRedirect = (path, validator = () => true, deps = []) => {
    const navigate = useNavigate()

    useEffect(() => {
        if (validator()) {
            navigate(path)
        }
    }, [path, navigate, validator, ...deps])
}

The useRedirect in OnboardingLayout is not working as intended because if the user object is now truthy (from null) the useEffect in the useRedirect custom hook is not triggered again even though I already passed a dependency. Also, spreading deps in the useEffect gives me a warning from eslint which says, "React Hook useEffect has a spread element in its dependency array. This means we can't statically verify whether you've passed the correct dependencies.".


Solution

  • There isn't anything you can do about the ESlint warning – it's entirely correct in that it can't help you now (and that's fine, it's just a warning that reminds you to be careful with that dep array).

    By a quick glance, your logic looks fine, it's just that your validator() implementation never returns anything but undefined.

    How about

    useRedirect("/c", () => {
      return user && Object.values(user.onboarding).every(e => e);
    }, [user])
    

    instead?

    (Using TypeScript would have, by the way, caught this, since a function that didn't return a boolean wouldn't pass for validator: () => boolean = () => true... :) )