{"id":29151206,"url":"https://github.com/karpeleslab/react-klbfw-hooks","last_synced_at":"2026-03-01T19:33:51.142Z","repository":{"id":57123987,"uuid":"238862944","full_name":"KarpelesLab/react-klbfw-hooks","owner":"KarpelesLab","description":"GET Hooks for klbfw","archived":false,"fork":false,"pushed_at":"2025-06-20T02:44:35.000Z","size":88,"stargazers_count":0,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-07-01T00:08:51.100Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/KarpelesLab.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-02-07T07:03:10.000Z","updated_at":"2025-03-16T15:07:08.000Z","dependencies_parsed_at":"2022-08-25T18:21:46.057Z","dependency_job_id":null,"html_url":"https://github.com/KarpelesLab/react-klbfw-hooks","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/KarpelesLab/react-klbfw-hooks","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KarpelesLab%2Freact-klbfw-hooks","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KarpelesLab%2Freact-klbfw-hooks/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KarpelesLab%2Freact-klbfw-hooks/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KarpelesLab%2Freact-klbfw-hooks/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/KarpelesLab","download_url":"https://codeload.github.com/KarpelesLab/react-klbfw-hooks/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KarpelesLab%2Freact-klbfw-hooks/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262870877,"owners_count":23377314,"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":[],"created_at":"2025-07-01T00:08:54.231Z","updated_at":"2026-03-01T19:33:51.104Z","avatar_url":"https://github.com/KarpelesLab.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# React Hooks for KLBFW\n\nA collection of React hooks and SSR utilities for [KarpelesLab Framework](https://github.com/KarpelesLab/klbfw).\n\n## Installation\n\n```bash\nnpm install @karpeleslab/react-klbfw-hooks\n```\n\n## Features\n\n* Shared state across components through named variables\n* SSR (Server-Side Rendering) with React\n* REST API integration with caching\n* React Router v7 support for modern routing with SSR\n* Promise handling for data loading during SSR\n\n## Available Hooks\n\n* **useRest(path, params, noThrow, cacheLifeTime)**: Fetches data from your backend with automatic caching and SSR support\n* **useVar(varName, defaultValue)**: Provides shared state accessible by name throughout your application\n* **useVarSetter(varName, defaultValue)**: Returns only a setter for the given variable without subscribing to updates\n* **usePromise(promise)**: Registers a promise for SSR to wait for before rendering\n* **useRestRefresh(path, params, cacheLifeTime)**: Returns only the refresh function for a REST endpoint\n* **useRestResetter()**: Returns a function to clear all REST cache (useful for logout)\n\n## Usage\n\n### run(routes, promisesOrOptions, options)\n\nThe entry point function that replaces ReactDOM.render/hydrate with SSR support. Takes a route configuration and optional settings.\n\n**Parameters:**\n- `routes`: A React Router route configuration created with `createRoutesFromElements` or directly as a route object\n- `promisesOrOptions`: Either an array of promises to wait for, or an options object\n- `options`: Configuration options (when using promises as the second parameter)\n\n**Options object properties:**\n- `routerProps`: Additional props to pass to the Router component (useful for injecting stores or providers)\n- `contextProps`: Additional props to pass to the internal Context.Provider\n\n#### Basic usage in your `index.js`:\n\n```javascript\nimport { run } from \"@karpeleslab/react-klbfw-hooks\";\nimport { Route, createRoutesFromElements } from \"react-router-dom\";\nimport Home from './routes/Home';\n\n// Create routes with the Data Router API\nconst routes = createRoutesFromElements(\n  \u003cRoute path=\"/\" element={\u003cHome /\u003e} /\u003e\n);\n\n// Pass the routes to run\nrun(routes);\n```\n\n#### Injecting additional props/providers:\n\n```javascript\nimport { run } from \"@karpeleslab/react-klbfw-hooks\";\nimport { Route, createRoutesFromElements } from \"react-router-dom\";\nimport { Provider } from 'react-redux';\nimport { store } from './store';\nimport Home from './routes/Home';\n\n// Create routes\nconst routes = createRoutesFromElements(\n  \u003cRoute path=\"/\" element={\u003cHome /\u003e} /\u003e\n);\n\n// Inject the Redux store by providing custom router props\nrun(routes, {\n  routerProps: {\n    // These props will be passed to the RouterProvider (client) or StaticRouterProvider (server)\n    fallbackElement: \u003cdiv\u003eLoading...\u003c/div\u003e,\n    future: {\n      v7_startTransition: true\n    }\n  },\n  contextProps: {\n    // You can also wrap the entire app with providers using React.createElement in your index.js\n    // This is an alternative approach for global store/provider setup\n  }\n});\n```\n\n#### With React Router v7:\n\n```javascript\nimport { run } from \"@karpeleslab/react-klbfw-hooks\";\nimport { redirect, Route, createRoutesFromElements } from \"react-router-dom\";\nimport Home from './routes/Home';\nimport About from './routes/About';\nimport Contact from './routes/Contact';\n\n// Create routes\nconst routes = createRoutesFromElements(\n  \u003c\u003e\n    \u003cRoute path=\"/\" element={\u003cHome /\u003e} /\u003e\n    \u003cRoute path=\"/about\" element={\u003cAbout /\u003e} /\u003e\n    \u003cRoute \n      path=\"/contact\" \n      element={\u003cContact /\u003e} \n      loader={async () =\u003e {\n        // Load data needed for this route\n        const data = await fetch('/api/contact-info').then(r =\u003e r.json());\n        return data;\n      }}\n    /\u003e\n    \u003cRoute \n      path=\"/redirect\" \n      loader={() =\u003e {\n        // Redirect example with status code\n        return redirect(\"/about\", 301);\n      }}\n    /\u003e\n  \u003c/\u003e\n);\n\n// Pass routes to run\nrun(routes);\n```\n\n### Server-Side Rendering with React Router v7\n\nThe library provides full support for React Router v7 SSR features including:\n\n- **Data Loading**: Routes with loaders will have their data pre-loaded during SSR\n- **Redirects**: Redirect responses from loaders are properly handled with status codes preserved\n- **Data Router API**: Uses the modern React Router v7 data APIs (createBrowserRouter, createStaticHandler, createStaticRouter, RouterProvider, StaticRouterProvider)\n\nUnder the hood, the implementation:\n\n1. On the client: Creates a browser router from routes using `createBrowserRouter`\n2. On the server: Creates a static handler from routes using `createStaticHandler`\n3. Processes routes with `query` function to detect redirects and load data\n4. Renders using `createStaticRouter` and `StaticRouterProvider` for SSR\n5. Preserves HTTP status codes (301, 302, etc.) for proper SEO\n\nThis allows you to use all modern React Router features while still benefiting from server-side rendering.\n\nWith i18n support:\n\n```javascript\nimport { run } from \"@karpeleslab/react-klbfw-hooks\";\nimport { Route } from \"react-router-dom\";\nimport Home from './routes/Home';\nimport i18n from 'i18next';\nimport { initReactI18next } from 'react-i18next';\nimport { Backend } from '@karpeleslab/i18next-klb-backend';\nimport { getLocale } from \"@karpeleslab/klbfw\";\n\nlet i18nOpt = {\n\tlng: getLocale(),\n\tinitImmediate: false,\n\tload: 'currentOnly',\n\tinterpolation: {\n\t\tescapeValue: false, // not needed for react as it escapes by default\n\t},\n\treact: {\n\t\tuseSuspense: false,\n\t}\n};\n\n// Define your routes as an array of \u003cRoute\u003e elements\nconst routes = [\n  \u003cRoute path=\"/\" element={\u003cHome /\u003e} key=\"home\" /\u003e\n];\n\nrun(routes, [i18n.use(Backend).use(initReactI18next).init(i18nOpt)]);\n```\n\n### useVar(varName, defaultValue)\n\nHook for creating/accessing named variables which share a value anywhere in the application.\n\n```javascript\nfunction Counter() {\n\tconst [count, setCount] = useVar(\"counter\", 0);\n\n\treturn (\n\t\t\u003cdiv\u003e\n\t\t\tCount is {count}\n\t\t\t\u003cbutton onClick={() =\u003e setCount(count + 1)}\u003eIncrement\u003c/button\u003e\n\t\t\u003c/div\u003e\n\t);\n}\n```\n\nIn another component:\n\n```javascript\nfunction DisplayCounter() {\n\tconst [count] = useVar(\"counter\", 0);\n\treturn \u003cdiv\u003eCurrent count: {count}\u003c/div\u003e;\n}\n```\n\n### useVarSetter(varName, defaultValue)\n\nReturns only a setter for the given variable, without subscribing the current component to variable updates.\n\n```javascript\nfunction CounterControl() {\n\tconst setCount = useVarSetter(\"counter\", 0);\n\treturn \u003cbutton onClick={() =\u003e setCount(0)}\u003eReset Counter\u003c/button\u003e;\n}\n```\n\n### usePromise(promise)\n\nRegisters a promise that the server needs to wait for in SSR before rendering. Useful for ensuring data is available during server-side rendering.\n\n```javascript\nfunction DataComponent() {\n\tconst [data, setData] = useState(null);\n\t\n\tuseEffect(() =\u003e {\n\t\tconst promise = fetchData().then(result =\u003e setData(result));\n\t\tusePromise(promise);\n\t}, []);\n\t\n\treturn \u003cdiv\u003e{data ? JSON.stringify(data) : \"Loading...\"}\u003c/div\u003e;\n}\n```\n\n### useRest(path, params, noThrow, cacheLifeTime)\n\nPerforms a REST GET request to the specified path, caching the result and returning it in a way that is safe for rendering.\n\n```javascript\nfunction UserProfile({ userId }) {\n\tconst [user, refreshUser] = useRest(`/api/users/${userId}`);\n\t\n\treturn (\n\t\t\u003cdiv\u003e\n\t\t\t{user ? (\n\t\t\t\t\u003c\u003e\n\t\t\t\t\t\u003ch2\u003e{user.name}\u003c/h2\u003e\n\t\t\t\t\t\u003cp\u003e{user.email}\u003c/p\u003e\n\t\t\t\t\t\u003cbutton onClick={refreshUser}\u003eRefresh\u003c/button\u003e\n\t\t\t\t\u003c/\u003e\n\t\t\t) : \"Loading...\"}\n\t\t\u003c/div\u003e\n\t);\n}\n```\n\nWith parameters:\n\n```javascript\nfunction SearchResults() {\n\tconst [query, setQuery] = useState(\"\");\n\tconst [results, refreshResults] = useRest(\"/api/search\", { q: query });\n\t\n\treturn (\n\t\t\u003cdiv\u003e\n\t\t\t\u003cinput \n\t\t\t\tvalue={query} \n\t\t\t\tonChange={e =\u003e setQuery(e.target.value)} \n\t\t\t/\u003e\n\t\t\t\u003cbutton onClick={refreshResults}\u003eSearch\u003c/button\u003e\n\t\t\t\n\t\t\t{results \u0026\u0026 results.map(item =\u003e (\n\t\t\t\t\u003cdiv key={item.id}\u003e{item.title}\u003c/div\u003e\n\t\t\t))}\n\t\t\u003c/div\u003e\n\t);\n}\n```\n\n## License\n\nMIT","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkarpeleslab%2Freact-klbfw-hooks","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkarpeleslab%2Freact-klbfw-hooks","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkarpeleslab%2Freact-klbfw-hooks/lists"}