Search code examples
reactjsreact-hooksreact-apolloreact-apollo-hooks

Why am I able to conditionally call a hook one way, but not the other?


Context: When I refresh the dashboard, useHasPermission makes an async call to determine if the user has access to somePermission.

Issue: hasPermission initially evaluates to false, but once the async call has completed hasPermission evaluates to true. This causes the useQuery, Apollo hook to not be called on the first render, and then called on the second render. The following error is shown:

"Rendered more hooks than during the previous render."

Question: Why does this error only happen in example A and not example B?

// Example A: Does not work
const Dashboard = () => {
  const hasPermission = useHasPermission([somePermission]);

  const getDashboardData = () => {
    const { loading, data, error } = useQuery(SOME_QUERY, {
      variables: { ...someVars }
    });
    return <Table ={data} loading={loading} error={error}><Table>
  };

  return (
    {hasPermission ? getDashboardData() : null}
    <Announcements></Announcements>
  )
}

// Example B: Works
const Dashboard = () => {
  const hasPermission = useHasPermission([somePermission]);

  const DashboardData = () => {
    const { loading, data, error } = useQuery(ACCOUNTS_FOR_CUSTOMER_DASHBOARD, {
      variables: { ...someVars }
    });
    return <Table ={data} loading={loading} error={error}><Table>
  };

  return (
    {hasPermission ? (
        <DashboardData></DashboardData>
      ) : null}
    <Announcements></Announcements>
  )
}

Solution

  • Hooks aren't meant to be conditionally used.

    In the first example, you are conditionally calling a function that uses a new hook and returns JSX, so this breaks the rules of hooks.

    In the second example, you are creating a new component DashboardData that mounts conditionally. So because it is a new component it is allowed.

    So the difference between the two is in "A" useQuery belongs to the Dashboard component, where in "B" it belongs to DashboardData.