1

Can we dynamically import hooks based on the value passed to the component?

For eg.

App.js

<BaseComponent isActive />

BaseComponent.js

if(props.isActive) {
  // import useActive (custom Hook)
}

I donot want these(custom hook) files to be imported and increase the size of BaseComponent even when the props contain falsey values.

priyanshu sinha
  • 553
  • 4
  • 13
  • Check out this thread: https://stackoverflow.com/questions/36367532/how-can-i-conditionally-import-an-es6-module#40277993 – Gh05d Jun 10 '20 at 08:17
  • Here I can see isActive is always true, so there's no point of importing it conditionally, And if the prop is not always true, so you must import useActive on the top level. – Siraj Alam Jun 10 '20 at 08:39

2 Answers2

2

You can dynamically import hooks as it is just a function (using require), but you shouldn't because you can't use hooks inside conditions.

See Rules of Hooks

Only call Hooks at the top level. Don’t call Hooks inside loops, conditions, or nested functions.

If you want conditionally use a hook, use the condition in its implementation (look for example at skip option of useQuery hook from Apollo GraphQL Client).

const useActive = (isUsed) => {
  if (isUsed) {
    // logic
  }
}
Dennis Vash
  • 42,190
  • 6
  • 81
  • 99
  • Will this not affect the size of the BaseComponent which did not require `useActive` at all is `props.isActive` is false? – priyanshu sinha Jun 10 '20 at 08:24
  • 2
    It will add a few **bytes** to the file size, but why you even consider it? Also, you don't have any other options as you restricted to React API, Please read: https://stackify.com/premature-optimization-evil/ – Dennis Vash Jun 10 '20 at 08:28
1

You should extract the logic inside the useActive hook and dynamically import it instead of dynamically importing the hook since you should not call Hooks inside loops, conditions, or nested functions., checkout Rules of Hooks:

Let's say your useActive hook was trying to update the document title (in real world, it has to be a big chunk of code that you would consider using dynamic import)

It might be implemented as below:

// useActive.js

import { useEffect } from "react";    
export function useActive() {
  useEffect(() => {
    document.title = "(Active) Hello World!";
  }, []);
}

And you tried to use it in the BaseComponent:

// BaseComponent.js

function BaseComponent({ isActive }) {
  if (isActive) { // <-- call Hooks inside conditions ❌
    import("./useActive").then(({ useActive }) => {
      useActive();
    });
  }
  return <p>Base</p>;
}

Here you violated the rule "don't call Hooks inside conditions" and will get an Invalid hook call. error.

So instead of dynamically import the hook, you can extract the logic inside the hook and dynamically import it:

// updateTitle.js

export function updateTitle() {
  document.title = "(Active) Hello World!"
}

And you do the isActive check inside the hook:

// BaseComponent.js

function BaseComponent({ isActive }) {
  useEffect(() => {
    if (!isActive) return;

    import("./updateTitle").then(({ updateTitle }) => {
      updateTitle();
    });
  }, [isActive]);

  return <p>Base</p>;
}

It works fine without violating any rules of hooks.

I have attached a CodeSandbox for you to play around:

Edit hardcore-wing-p3uvc

hangindev.com
  • 3,683
  • 8
  • 24