Ozan
Ozan

Reputation: 259

How to run React custom hook conditionally or inside a function

I have a custom hook to redirect users to edit page. On index page I can duplicate items and delete. I can redirect users after duplicate, but the problem is when I delete an item, this custom hook redirects users to edit page again. So I need to find a way to make it work conditionally.

Custom hook:

export default function useDuplicateItem(url: string) {
  const { sendRequest: duplicate } = useHttpRequest();

  const duplicateItem = useCallback(
    (data) => {
      duplicate([
        {
          url: `/api/server/${url}`,
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
          },
          data,
        },
      ]);
    },
    [duplicate, url]
  );
  useRedirectEditPage(url); // This causes the problem
  return duplicateItem;
}

index page:

 const duplicateItem = useDuplicateItem('documents'); 
// custom hook rendered here, which is not correct. I want to run it when duplicate function runs.
    
      const duplicate = useCallback(() => {
        const data = {
          name: copiedName,
          sources: singleDocument?.sources,
          document: singleDocument?.document,
          tool: singleDocument?.tool,
          access: singleDocument?.access,
        };
        duplicateItem(data);
      }, [copiedName, duplicateItem, singleDocument]);

useRedirectEditPage:

export default function useRedirectEditPage(slug: string) {
  const { saveResponses, setSaveResponses, setHeaderStates } =
    useAdminContext();
  const router = useRouter();

  useEffect(() => {
    const statusCodes: number[] = [];
    let id;

    saveResponses.forEach((value) => {
      statusCodes.push(value?.status);
      id = value?.id;
    });

    if (statusCodes.length && id) {
      if (statusCodes.includes(404)) {
        setHeaderStates((prev) => ({
          ...prev,
          canBeSaved: false,
        }));
      } else {
        router.push(`/admin/${slug}/edit/${id}`);
        setSaveResponses(new Map());
      }
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [saveResponses, router, setSaveResponses]);
}

saveResponses state is coming after I make any request to server, and I am able to get id to redirect users. I use new Map() to set data inside saveResponses.

Upvotes: 0

Views: 240

Answers (1)

Nizar Zizoune
Nizar Zizoune

Reputation: 514

From the react docs:

Don’t call Hooks inside loops, conditions, or nested functions. Instead, always use Hooks at the top level of your React function, before any early returns. By following this rule, you ensure that Hooks are called in the same order each time a component renders. That’s what allows React to correctly preserve the state of Hooks between multiple useState and useEffect calls. (If you’re curious, we’ll explain this in depth below.)

React relies on the order in which Hooks are called to know which setState corresponds to which state, calling them inside a condition will mess up the previous mechanism.

I would recommend to read the following: https://reactjs.org/docs/hooks-rules.html#explanation

Upvotes: 1

Related Questions