skip to Main Content

I have a react and next project which uses multiple pages with a similar structure. In each page we are using custom hooks to load data, so it looks something like:

  const theme = useTheme()
  const router = useRouter()
  const { state, dispatch } = useContext(Context)
  const { config, metaData } = router.query
  const getQueryPath1 = router.query.path1
  const getQueryPath2 = router.query.path2
  const { siteConfig } = useSiteConfig()
  const { partnerAgency } = usePartnerAgency(siteConfig?.agency_prop)
  const { partnerParameters } = usePartnerParameters()
  const { forms } = useForms(partnerParameters, metaData)
  const environment = useEnvironment()

and so on.

As we are using much of these hooks/configs across multiple components (actually next.js 12 pages) I wondered if there was a strategy for combining these under one parent or umbrella hook. This of course feels like it very much goes against the intended usage of hooks, but there must be a way to reduce repetition in the code.

I have tried to create a custom component which would utilize all these hooks but it ended up being not very configurable, and didn’t have the intended outcome of reducing repetition.

Any advice would be appreciated – thanks in advance.

2

Answers


  1. You could move all common hooks into a custom hook to de-clutter you page components and to make the whole declaration shebang re-usable.

    const useCommonHooks = () => {
      const theme = useTheme()
      const router = useRouter()
      const { state, dispatch } = useContext(Context)
      const { config, metaData } = router.query
      const getQueryPath1 = router.query.path1
      const getQueryPath2 = router.query.path2
      const { siteConfig } = useSiteConfig()
      const { partnerAgency } = usePartnerAgency(siteConfig?.agency_prop)
      const { partnerParameters } = usePartnerParameters()
      const { forms } = useForms(partnerParameters, metaData)
      const environment = useEnvironment()
      return {
        theme,
        router,
        state,
        dispatch,
        config,
        metaData,
        getQueryPath1,
        getQueryPath2,
        siteConfig,partnerAgency,
        partnerParameters,
        forms,
        environment,
      }
    }
    

    usage

    const {
        theme,
        router,
        state,
        dispatch,
        config,
        metaData,
        getQueryPath1,
        getQueryPath2,
        siteConfig,partnerAgency,
        partnerParameters,
        forms,
        environment,
      } = useCommonHooks()
    

    But this is not a silver bullet; I usually only put things together in a custom hook that have strong cohesion – this is not the case here, they are really rather unrelated and only have one thing in common: to usually all be used by your typical page component.
    And be aware that this reduces flexibility for you; with this approach you cannot omit a hook that’s not really needed on a page, or swap out the form hook for example.
    And it is also quite unwieldy with its 12 properties.

    I probably would just accept that most page components will have a copy-and-pasted block of hook delarations at the very top. Maybe even sourround it with a comment bracket to clearly show this block is shared.

    // -------- common page hooks --------
    // please add a comment here if this page
    // deviates in anything within this common block
      const theme = useTheme()
      const router = useRouter()
      const { state, dispatch } = useContext(Context)
      const { config, metaData } = router.query
      const getQueryPath1 = router.query.path1
      const getQueryPath2 = router.query.path2
      const { siteConfig } = useSiteConfig()
      const { partnerAgency } = usePartnerAgency(siteConfig?.agency_prop)
      const { partnerParameters } = usePartnerParameters()
      const { forms } = useForms(partnerParameters, metaData)
      const environment = useEnvironment()
    // -------- common page hooks --------
    
    Login or Signup to reply.
  2. You should combine code with a single purpose into a custom hook. The main idea is to encapsulate the implementation details, and thus avoid the repetition.

    However, combining unrelated logic to a single hook just to avoid repetition, would make your code inflexible. Anytime you’ll need to change anything inside the master hook, you’ll need to go over all your pages to adapt.

    From what I can see from your logic, you can extract 2 common hooks.

    Hook 1 – useRouting:

    const useRouting = () => {
      const router = useRouter()
      const { state, dispatch } = useContext(Context)
      const { config, metaData } = router.query
      
      return {
        getQueryPath1: router.query.path1,
        getQueryPath2: router.query.path2
      }
    }
    

    Hook 2 – useForms:

    const useForms = () => {
      const { siteConfig } = useSiteConfig()
      const { partnerAgency } = usePartnerAgency(siteConfig?.agency_prop)
      const { partnerParameters } = usePartnerParameters()
      const { forms } = useForms(partnerParameters, metaData)
      
      return forms;
    }
    

    Now you can use the domain specific hooks in your components:

    const { getQueryPath1, getQueryPath2 } = useRouting()
    const forms = useForms()
    const theme = useTheme()
    const environment = useEnvironment()
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search