1

In a React function component (with TypeScript) I need to call two different custom hooks depending on a prop's value, considering that each hook is called through its own service by requesting an API which is forbidden for the other hook.

As React rules prohibit calling a hook conditionally, I try to figure out how to get a hook result depending on who is calling it.

So I first tried to call the hook conditionally (which is against the React rules):

import React from "react";
import { useMyTeachers } from "/services/student-service";
import { useMyStudents } from "/services/teacher-service";

interface MyComponentProps {
    role: string;
}

export const MyComponent: React.FC<MyComponentProps> = ({ role }) => {
    let myList;
    if (role == "student") {
        myList = useMyTeachers();
    }
    if (role == "teacher") {
        myList = useMyStudents();
    }
    ...
}

Then I tried to call both hooks unconditionally:

export const MyComponent: React.FC<MyComponentProps> = ({ role }) => {
    const myTeachersList = useMyTeachers(); //requesting a for-student-use-only API
    const myStudentsList = useMyStudents(); //requesting a for-teacher-use-only API
    ...
}

But in this case, a forbidden error is thrown in console because of the API restriction.

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
Fred B.
  • 21
  • 1
  • 2
    You can render components conditionally, and those components can call different hooks. Or maybe decouple the data fetching from React internals so you can call it conditionally. – jonrsharpe May 12 '23 at 07:53
  • What is the difference between these two hooks? Maybe you can change it to only one – Konrad May 12 '23 at 08:08
  • I effectively could render two different components conditionally. In fact that was my very first version. But I'd lose the refactored aspect. I wrote this compo precisely to avoid duplicated code. But maybe this approach is not compatible with React rules :) – Fred B. May 12 '23 at 08:11
  • Konrad, each hook calls a different backend route which is not allowed fo the other. – Fred B. May 12 '23 at 08:16
  • I agree with @jonrsharpe - just to elucidate: you could conditionally render one of two data components which have a `onData` prop like `` and ``. However I think it's better as he suggested to have your API service layer agnostic of hooks, and if you want `useMyTechers/Students` then this is just a very thin wrapper over the API service layer - so adding an extra `useMyTeachersOrStudents` hook is virtually no extra code - just conditionally calls either API service function based on role – Dominic May 12 '23 at 08:18

1 Answers1

1

As React rules prohibit calling a hook conditionally, you can add if else in your custom hook and pass param to it. like this:

function useMyList(role) {
  const [state, setState] = useState([])
  const [loading, setLoading] = useState(false)
  useEffect(async () => {
    let myList = []
    setLoading(true)
    if (type === 'student') {
      // request student
      myList = await requestGetStudents;
    } 
    if (role == "teacher") {
      // request teacher
      myList = await requestGetTeachers;
    }
    setLoading(false)
    setState(myList)
  }, [role])
  return [state, loading]
}
Sky Clong
  • 141
  • 1
  • 8