{"id":16125742,"url":"https://github.com/dy/enhook","last_synced_at":"2025-09-12T21:33:15.526Z","repository":{"id":41124917,"uuid":"218877583","full_name":"dy/enhook","owner":"dy","description":"Enable hooks for a function","archived":false,"fork":false,"pushed_at":"2023-01-04T23:55:23.000Z","size":2158,"stargazers_count":25,"open_issues_count":20,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-12-28T06:41:52.252Z","etag":null,"topics":["hooks","hooks-api-react","reactive","unihooks"],"latest_commit_sha":null,"homepage":"","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/dy.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":"2019-10-31T23:24:19.000Z","updated_at":"2024-11-06T22:59:22.000Z","dependencies_parsed_at":"2023-02-03T00:46:48.912Z","dependency_job_id":null,"html_url":"https://github.com/dy/enhook","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/dy%2Fenhook","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dy%2Fenhook/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dy%2Fenhook/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dy%2Fenhook/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dy","download_url":"https://codeload.github.com/dy/enhook/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":232792150,"owners_count":18577262,"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":["hooks","hooks-api-react","reactive","unihooks"],"created_at":"2024-10-09T21:31:23.681Z","updated_at":"2025-01-06T21:54:51.173Z","avatar_url":"https://github.com/dy.png","language":"JavaScript","readme":"# enhook [![Build Status](https://travis-ci.org/unihooks/enhook.svg?branch=master)](https://travis-ci.org/unihooks/enhook) [![unstable](https://img.shields.io/badge/stability-unstable-yellow.svg)](http://github.com/badges/stability-badges)\n\nEnable react/preact/∀ hooks for regular functions.\n\n[![NPM](https://nodei.co/npm/enhook.png?mini=true)](https://nodei.co/npm/enhook/)\n\n```js\nimport enableHooks from 'enhook'\nimport { useState, useEffect } from 'any-hooks'\n\nlet countFrom = enableHooks(initCount =\u003e {\n  let [count, setCount] = useState(initCount)\n\n  setTimeout(() =\u003e {\n    setCount(++count)\n  }, 1000)\n\n  // any side-effects\n  useEffect(() =\u003e console.log(count), [count])\n})\n\ncountFrom(0)\n```\n\n_Enhook_ turns any function into reactive function with enabled hooks for a given framework.\nThe framework is by default detected from the list:\n\n* [x] [`react`](https://ghub.io/react)\n* [x] [`preact`](https://ghub.io/preact)\n* [x] [`rax`](https://ghub.io/rax)\n* [x] [`haunted`](https://ghub.io/haunted)\n* [x] [`augmentor`](https://ghub.io/augmentor)\n* [x] [`atomico`](https://ghub.io/atomico)\n* [x] [`fuco`](https://ghub.io/fuco)\n* [x] [`tng-hooks`](https://ghub.io/tng-hooks) (passive)\n\u003c!-- * [ ] [`dom-augmentor`](https://ghub.io/dom-augmentor) --\u003e\n\u003c!-- * [ ] [`neverland`](https://ghub.io/neverland) --\u003e\n\u003c!-- * [ ] [`fn-with-hooks`](https://ghub.io/fn-with-hooks) (passive) --\u003e\n\n\nIn case of ES modules autodetection is not available (until `import.meta.resolve()` or `await import()` is available), you have to manually indicate framework to use.\n\n```js\nimport * as preact from 'preact'\nimport preactHooks from 'preact/hooks'\nimport enhook from 'enhook'\nimport setHooks, { useState } from 'any-hooks'\n\nenhook.use(preact) // or enhook.use(React, ReactDOM)\nsetHooks(preactHooks)\n\n// now enhook uses preact with  as base\nlet fn = enhook(() =\u003e {\n  let [count, setCount] = useState(0)\n  //...\n})\n```\n\n\n## API\n\n### `fn = enhook(fn, { passive=false }?)`\n\nCreate function wrapper, allowing hooks in function body. `passive` option may define if function must be reactive.\n\n```js\nimport enhook from 'enhook'\nimport { useState } from 'any-hooks'\n\nlet passiveFn = enhook((i) =\u003e {\n  let [count, setCount] = useState(0)\n\n  // this does not cause self-recursion in passive mode\n  setCount(i)\n}, { passive: true })\n\npassiveFn(1)\npassiveFn(2)\n```\n\n#### `fn.unhook()`\n\nTeardown enhooked function. This will dispose all `useEffect`s. Any subsequent calls to that function will throw an error.\n\n\u003c!--\n## Use-cases\n\n### 1. React/preact hooks anywhere\n\nOrganize non-DOM reactions with existing react hooks.\n\n```js\nimport hooked from 'enhook'\nimport { useRoute } from 'wouter'\n\nlet observeRoute = hooked((route, callback) =\u003e {\n  const [match, params] = useRoute(route)\n  if (match) {\n    callback(params)\n    return params\n  }\n})\n\nobserveRoute('/user/:id', ({ id }) =\u003e {})\nobserveRoute('/org/:id', ({ id }) =\u003e {})\n```\n\nSee [any-hooks](https://ghub.io/any-hooks) for aliasing react, in case if react is not installed.\n\n### 2. Functional custom elements\n\nMake function-controlled custom elements à la [haunted](https://ghub.io/haunted) or [remount](https://ghub.io/remount).\n\n```js\nimport hooked from 'enhook'\nimport { html, render } from 'lit-html'\nimport useSWR from 'swr'\n\nfunction MyComponent () {\n  let { data, error } = useSWR('/api/user', fetch)\n\n  // renderer can be any, not necessary lit-html\n  if (error) return render(html`Failed to load`, this)\n  if (!data) return render(html`Loading...`, this)\n\n  render(html`Hello, ${ data.name }`, this)\n}\n\ncustomElements.define('my-component', class { constructor () { hooked(MyComponent).call(this) } })\n```\n\n### 3. Methods with hooks\n\nMake class methods support hooks, even react components themselves, like [react-universal-hooks](https://ghub.io/react-universal-hooks).\n\n```js\nimport hooked from 'enhook'\nimport { Component } from 'react'\n\nclass MyComponent extends Component {\n  // can be implemented as @hooked decorator\n  render() {\n    let [count, setCount] = useState(0)\n    setTimeout(() =\u003e setCount(++count), 1000)\n    return \u003c\u003e{ count }\u003c/\u003e\n  }\n}\nMyComponent.prototype.render = hooked(MyComponent.prototype.render)\n```\n\n### 4. [wait for it]\n\n### 4. Functional components reactive framework\n\nHyperscript with functional components would look like:\n\n```js\n// nanoreact.js\nimport htm from 'htm'\nimport hooky from 'enhook'\nimport morph from 'nanomorph'\nimport h from 'hyperscript'\nimport { usePrev } from 'nanohook'\n\nconst html = htm.bind((tag, props, ...children) =\u003e {\n  if (typeof tag === 'function') return hooky(props =\u003e {\n    return morph(prev, tag(props))\n  })({ children, ...props })\n\n  return h(tag, props, ...children)\n})\n\nconst render = (what, where) =\u003e morph(where, what)\n\nexport { html, render }\n```\n\n```js\n// app.js\nimport { useState, useEffect, html, render } from './nanoreact'\n\nfunction CounterApp () {\n  let [count, setCount] = useState(0)\n\n  return html`\u003cdiv\u003e${ count }\u003c/div\u003e`\n}\n\nrender(html`\u003c${CounterApp}/\u003e`, document.getElementById('app'))\n```\n\n\n### 5. Stream / observable / async iterators etc.\n\n```js\nimport hooked, { useEffect } from 'enhook'\n\nlet observable = new Observable(hooked(observer =\u003e {\n  // ...calculating code\n\n  useEffect(() =\u003e {\n    // push changes into observable\n    observer.next(deps)\n  }, deps)\n\n  return () =\u003e {} // destruct\n})\n```\n--\u003e\n\n## See also\n\n* [unihooks](https://github.com/unihooks/unihooks) - unified all-framework essential hooks collection.\n\n## License\n\nMIT\n\n\u003cp align=\"right\"\u003eHK\u003c/p\u003e\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdy%2Fenhook","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdy%2Fenhook","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdy%2Fenhook/lists"}