{"id":21885569,"url":"https://github.com/sheraff/use-imported-hook","last_synced_at":"2025-04-15T07:41:42.193Z","repository":{"id":57388135,"uuid":"374060753","full_name":"Sheraff/use-imported-hook","owner":"Sheraff","description":null,"archived":false,"fork":false,"pushed_at":"2021-11-22T13:03:17.000Z","size":171,"stargazers_count":4,"open_issues_count":5,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-03T10:44:49.024Z","etag":null,"topics":["babel-plugin","dynamic","hooks","import","jsx","lazy-loading","loader","reactjs","webpack"],"latest_commit_sha":null,"homepage":"https://npmjs.com/package/use-imported-hook","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Sheraff.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-06-05T08:25:52.000Z","updated_at":"2023-05-18T18:14:59.000Z","dependencies_parsed_at":"2022-09-14T17:02:47.192Z","dependency_job_id":null,"html_url":"https://github.com/Sheraff/use-imported-hook","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Sheraff%2Fuse-imported-hook","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Sheraff%2Fuse-imported-hook/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Sheraff%2Fuse-imported-hook/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Sheraff%2Fuse-imported-hook/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Sheraff","download_url":"https://codeload.github.com/Sheraff/use-imported-hook/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249030717,"owners_count":21201347,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["babel-plugin","dynamic","hooks","import","jsx","lazy-loading","loader","reactjs","webpack"],"created_at":"2024-11-28T10:28:03.636Z","updated_at":"2025-04-15T07:41:42.164Z","avatar_url":"https://github.com/Sheraff.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# use-imported-hook\n\n[![unit tests](https://github.com/Sheraff/use-imported-hook/actions/workflows/tests.yml/badge.svg?branch=main)](https://github.com/Sheraff/use-imported-hook/actions/workflows/tests.yml)\n![gzipped size](https://badgen.net/badge/gzip/341%20bytes/cyan)\n[![PRs welcome](https://img.shields.io/badge/PRs-welcome-green)](https://github.com/Sheraff/use-imported-hook/issues)\n\n\n## Description\n\nThis package allows you to dynamically import any hook in a React component!\n\n🎉 Lazy load a component's logic 🎉\n```jsx\n// MyComponent.jsx (importer)\nimport useImportedHook from 'use-imported-hook/hook'\n\nexport default function MyComponent() {\n\tconst [load, setLoad] = useState(false)\n\tuseImportedHook(\n\t\tload \u0026\u0026 import('./useLazyHook.jsx'),\n\t)\n\treturn (\n\t\t\u003cbutton onClick={() =\u003e setLoad(true)}\u003e\n\t\t\tClick me\n\t\t\u003c/button\u003e\n\t)\n}\n```\n\n🎉 Lazy load a custom hook 🎉\n```jsx\n// useHook.jsx (importer)\nimport useImportedHook from 'use-imported-hook/hook'\n\nexport default function useHook({load, ...props}) {\n\treturn useImportedHook(\n\t\tload \u0026\u0026 import('./useLazyHook.jsx'),\n\t\tprops\n\t)\n}\n```\n\n🎉 And still write your importable hook like any hook you're used to 🎉\n```jsx\n// useLazyHook.jsx (importee)\nimport { useEffect, useCallback, useState } from 'react'\n\n/* @__IMPORTABLE_HOOK__ */\nexport default function useLazyHook({a, b, c}) {\n\tconst [d, setD] = useState(false)\n\n\tuseEffect(() =\u003e {\n\t\t// ...\n\t}, [a, b])\n\n\treturn useCallback(() =\u003e {\n\t\t// ...\n\t}, [c])\n}\n```\n\n\nIn the examples above, `useLazyHook` will only be loaded *if* `load` is true. This allows you to defer the loading of most of your components' logic (everything that isn't needed for the initial render).\n\n## Setup\n\n1. install the package\n\t```bash\n\tnpm i --save use-imported-hook\n\t```\n\n2. add the Babel plugin to your config\n\t```js\n\t// .babelrc.js\n\tmodule.exports = {\n\t\t// ...\n\t\tplugins: [\n\t\t\t'module:use-imported-hook'\n\t\t]\n\t}\n\t```\n\n## Syntax for `useImportedHook`\n\n```ts\nuseImportedHook\u003cT, U\u003e(\n\timportPromise: false | Promise\u003c{default: (args: T) =\u003e U}\u003e,\n\tparameters: T?,\n\tdefaultReturn: U?\n): U\n```\n\n| Argument        | Required | Example\n| --------------- | -------- | -------------\n| `importPromise` | `true`   | `bool \u0026\u0026 import('./path.jsx')`\n| `parameters`    | `false`  | `{ a, b }`\n| `defaultReturn` | `false`  | `\"\"`\n\n\u003cbr/\u003e\n\n**Parameters**\n- `importPromise` (required)\n\n\tcan either be *falsy* in which case the hook won't be loaded, or it can be a the *promise* returned by `import()`. By using it in combination with `import()`, webpack is able to package the hook in a separate chunk and to load it on demand.\n\n\t- ❗ The path passed to `import()` must be a relative path for babel to resolve it properly\n\n\t\t[![PRs welcome](https://img.shields.io/badge/PRs-welcome-green)](https://github.com/Sheraff/use-imported-hook/issues/1)\n\n\t\t```jsx\n\t\t❌ useImportedHook(bool \u0026\u0026 import('/src/hooks/useHook.jsx'))\n\t\t```\n\t\t```jsx\n\t\t❌ useImportedHook(bool \u0026\u0026 import('@alias/useHook.jsx'))\n\t\t```\n\t\t```jsx\n\t\t✅ useImportedHook(bool \u0026\u0026 import('./useHook.jsx'))\n\t\t```\n\t- ❗ The path passed to `import()` must be a string literal for babel to run a *static code* analysis\n\n\t\t![PRs won't fix](https://img.shields.io/badge/PRs-won't%20fix-red)\n\n\t\t```jsx\n\t\t❌ useImportedHook(bool \u0026\u0026 import(`./${hook}.jsx`))\n\t\t```\n\t\t```jsx\n\t\t✅ useImportedHook(bool \u0026\u0026 import('./useHook.jsx'))\n\t\t```\n\n- `parameters` (optional)\n\n\tis optional and will default to `{}`. Do note that it is a single argument, so if you need to pass more than one thing to your hook, you can use `{a, b, c}` or `[a, b, c]`.\n\n- `defaultReturn` (optional)\n\n\tThe *return* value of `useImportedHook` as long as the hook hasn't loaded yet. \n\n**Return value**\n\n- While `importPromise` is either falsy or pending, `useImportedHook` returns `defaultReturn`. \n\n- Once `importPromise` is truthy *and* resolves, `useImportedHook` returns whatever the imported hook returns.\n\n## Syntax for the imported hook\n\n❗ Because we do static code analysis with a Babel transform plugin to achieve this result, there are a few requirements to keep in mind:\n\n- The function containing all the built-in hooks must be the default export\n\t```jsx\n\t❌ function withHooks() {\n\t❌\tuseEffect(() =\u003e {/*...*/})\n\t❌ }\n\t❌ export default function() {\n\t❌\twithHooks()\n\t❌ }\n\t```\n\t```jsx\n\t✅ function withHooks() {\n\t✅\tuseEffect(() =\u003e {/*...*/})\n\t✅ }\n\t✅ export default withHooks\n\t```\n- The function containing all the built-in hooks must be labeled with a leading comment containing the exact string `@__IMPORTABLE_HOOK__`\n\t```jsx\n\t/* @__IMPORTABLE_HOOK__ */\n\texport default function() {\n\t\tuseEffect(() =\u003e {/*...*/})\n\t}\n\t```\n- All of your built-in hooks must be in a single function \n\t\n\t![PRs won't fix](https://img.shields.io/badge/PRs-won't%20fix-red)\n\n\t```jsx\n\t❌ function moreStuff() {\n\t❌\tuseEffect(() =\u003e {\n\t❌\t\t// ...\n\t❌\t})\n\t❌ }\n\n\t/* @__IMPORTABLE_HOOK__ */\n\texport default function useLazyHook() {\n\t❌\tmoreStuff()\n\t\treturn useCallback(() =\u003e { /* ... */ })\n\t}\n\t```\n\n\t```jsx\n\t/* @__IMPORTABLE_HOOK__ */\n\texport default function useLazyHook() {\n\t✅\tuseEffect(() =\u003e {\n\t✅\t\t// ...\n\t✅\t})\n\t\treturn useCallback(() =\u003e { /* ... */ })\n\t}\n\t```\n- An imported hook can't contain a call to `useImportedHook`\n\t\n\t[![PRs welcome](https://img.shields.io/badge/PRs-welcome-green)](https://github.com/Sheraff/use-imported-hook/issues)\n\n\t```jsx\n\t/* @__IMPORTABLE_HOOK__ */\n\texport default function useLazyHook() {\n\t❌\tuseImportedHook(bool \u0026\u0026 import('./useOtherHook.jsx'))\n\t\treturn useCallback(() =\u003e { /* ... */ })\n\t}\n\t```\n\n- Not all initial values for `useState` and `useRef` can be extracted statically\n\n\t[![PRs welcome](https://img.shields.io/badge/PRs-welcome-green)](https://github.com/Sheraff/use-imported-hook/issues/3)\n\t- Allowed initial values\n\t\t- ✅ `true` and `false`\n\t\t- ✅ `0`, `1`, `2`... (all integers)\n\t\t- ✅ `0.5`, `.1`... (all floats)\n\t\t- ✅ `\"\"`, `\"hello world\"` (all strings)\n\t\t- ✅ `{}` (empty object)\n\t\t- ✅ `[]` (empty array)\n\t\t- ✅ `{a: 1}` (non-empty objects if values are themselves allowed values)\n\t\t- ✅ `[0, 1]` (non-empty arrays if items are themselves allowed values)\n\t\t- ✅ `!0`, `-1` (unary expressions)\n\t\t- ✅ `null`, `undefined`, `NaN`, `Infinity`\n\t- Forbidden initial values\n\t\t- ❌ `myVar` (variable identifiers)\n\t\t- ❌ `` `hello ${\"world\"}` `` (template literals)\n\t\t- ❌ `() =\u003e {}` (functions and arrow functions)\n\n\n## Limitation: forbidden built-in hooks\n[![PRs welcome](https://img.shields.io/badge/PRs-welcome-green)](https://github.com/Sheraff/use-imported-hook/issues)\n\nCurrently, only a subset of all built-in Hooks in React are supported *inside* the imported hook:\n- ✅ `useEffect`\n- ✅ `useCallback`\n- ✅ `useMemo`\n- ✅ `useLayoutEffect`\n- ✅ `useImperativeHandle`\n- ✅ `useDebugValue`\n- ✅ `useState`\n- ✅ `useRef`\n- ❌ `useReducer`\n- ❌ `useContext`\n\nIf your imported hook needs to use unsupported built-in hooks, the best approach is to declare the unsupported hooks before `useImportedHook` and pass them as arguments:\n\n```jsx\n// useHook.jsx (importer)\nimport { useContext } from 'react'\nimport useImportedHook from 'use-imported-hook/hook'\n\nexport default function useHook({shouldLoad, ...props}) {\n\tconst a = useContext(MyContext)\n\tuseImportedHook(\n\t\tshouldLoad \u0026\u0026 import('./useLazyHook.jsx'),\n\t\t{...props, a}\n\t)\n}\n```\n```jsx\n// useLazyHook.jsx (importee)\nimport { useEffect } from 'react'\n\n/* @__IMPORTABLE_HOOK__ */\nexport default function useLazyHook({a, b}) {\n\tuseEffect(() =\u003e {\n\t\tconsole.log(a) // value of `MyContext` provider\n\t}, [a, b])\n}\n```\n\n## Limitation: multiple `useImportedHook` per component \n[![PRs welcome](https://img.shields.io/badge/PRs-welcome-green)](https://github.com/Sheraff/use-imported-hook/issues/2)\n\nCurrently, we don't support importing several hooks from within a single component (or hook).\n\n```jsx\nexport default function MyComponent() {\n❌\tuseImportedHook(a \u0026\u0026 import('./hook1.jsx'))\n❌\tuseImportedHook(b \u0026\u0026 import('./hook2.jsx'))\n\treturn \u003c\u003e\u003c/\u003e\n}\n```\n\n## Managing Webpack chunks\n\nIf you have several components that will load their hooks at the same time, you can give a clue to webpack to package them together in the same chunk:\n\n```jsx\nexport default function ChatComponent({userLoggedIn}) {\n\tuseImportedHook(userLoggedIn \u0026\u0026 import(\n\t\t/* webpackMode: \"lazy-once\" */\n\t\t/* webpackChunkName: \"user-logged-in\" */\n\t\t'./useChatHook.jsx'),\n\t)\n\treturn \u003c\u003e\u003c/\u003e\n}\n```\n\n```jsx\nexport default function AccountSettings({userLoggedIn}) {\n\tuseImportedHook(userLoggedIn \u0026\u0026 import(\n\t\t/* webpackMode: \"lazy-once\" */\n\t\t/* webpackChunkName: \"user-logged-in\" */\n\t\t'./useSettingsHook.jsx'),\n\t)\n\treturn \u003c\u003e\u003c/\u003e\n}\n```\n\nIn the above example, webpack will put both `useChatHook.jsx` and `useSettingsHook.jsx` in the same .js chunk file.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsheraff%2Fuse-imported-hook","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsheraff%2Fuse-imported-hook","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsheraff%2Fuse-imported-hook/lists"}