0

I created a custom useOrganisation hook to fetch and manipulate data from my API which look something along the lines of:

export function useOrganisation({ organisationId }) { const [organisation, setOrganisation] = useState() // Load organisation useEffect(() => { loadOrganisation({ organisationId, setOrganisation }) }, [organisationId]) return { organisation, setOrganisation } } async function loadOrganisation({ organisationId, setOrganisation }) { const data = await fetchOrganisationData(organisationId) setOrganisation(data) } 

This works well when I call it from within a component where I need to display information for a single organisation, because I use the hook to fetch that one specific organisation, however, when I want to use it on a dashboard-like page to load multiple organisations simultaneously, I'm unable to do so since I cannot call the hook from within a look like such:

export default function OrganisationsDashboard() { const [organisations, setOrganisations] = useState([]) const organisationIds = ['org1', 'org2', 'org3'] organisationIds.forEach(orgId => { setOrganisations(prevState => { const { organisation } = useOrganisation(orgId) const stateCopy = [...prevState] copy.push(organisation) return copy }) }) } 

What is the correct way to re-use the hook logic when needing to load multiple organisations into an array like in the mock component above?

1
  • Don’t call Hooks inside loops, conditions, or nested functions. The official documentation may help you: Rules of Hooks. Commented Aug 8, 2022 at 7:26

1 Answer 1

1

You can customize your hook, to fetch a list of organizations, like this:

export function useOrganisation({ organisationIds }) { const [organisations, setOrganisations] = useState([]); // Load organisations useEffect(() => { loadOrganisations({ organisationIds, setOrganisations }) }, [organisationIds]) return { organisations, setOrganisations } } async function loadOrganisations({ organisationIds, setOrganisations }) { const orgs = []; for(let i=0; i < organisationIds.length; i++) { const data = await fetchOrganisationData(organisationIds[i]); orgs.push(data); } setOrganisations(orgs); } 

This can be used, in a component to get a single org, or in a dashboard to show multiple organizations, without having to use the hook in a loop.

Or, as using hooks in a loop is not recommended, you can write a useEffect within your dashboard component to fetch a list of organizations and reuse some of your code. Like this:

export function useOrganisation({ organisationId }) { const [organisation, setOrganisation] = useState() // Load organisation useEffect(() => { const org = loadOrganisation({ organisationId }); setOrganisation(org); }, [organisationId]) return { organisation, setOrganisation } } export async function loadOrganisation({ organisationId }) { const data = await fetchOrganisationData(organisationId) return data; } export default function OrganisationsDashboard() { const [organisations, setOrganisations] = useState([]); useEffect(() => { const organisationIds = ['org1', 'org2', 'org3']; fetchOrganisations(organisationIds); }, []); async fetchOrganisations(orgIds) { const orgs = []; for(let i=0; i < orgIds.length; i++) { let org = await loadOrganisation({organisationId: orgIds[i]}); orgs.push(org); } setOrganisations(orgs); } } 
Sign up to request clarification or add additional context in comments.

2 Comments

I want to re-use existing logic instead of re-writing the entire hook changing the internal data structure. The actual hook logic is much more complicated and would break with this.
There will some tradeoffs there, you might want to write a useEffect, in your dashboard application then, to fetch orgs, as using hooks in a loop is not recommended

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.