https://github.com/karpeleslab/react-klbfw-hooks
GET Hooks for klbfw
https://github.com/karpeleslab/react-klbfw-hooks
Last synced: 4 months ago
JSON representation
GET Hooks for klbfw
- Host: GitHub
- URL: https://github.com/karpeleslab/react-klbfw-hooks
- Owner: KarpelesLab
- Created: 2020-02-07T07:03:10.000Z (over 6 years ago)
- Default Branch: master
- Last Pushed: 2025-06-20T02:44:35.000Z (12 months ago)
- Last Synced: 2025-07-01T00:08:51.100Z (12 months ago)
- Language: JavaScript
- Size: 85.9 KB
- Stars: 0
- Watchers: 1
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# React Hooks for KLBFW
A collection of React hooks and SSR utilities for [KarpelesLab Framework](https://github.com/KarpelesLab/klbfw).
## Installation
```bash
npm install @karpeleslab/react-klbfw-hooks
```
## Features
* Shared state across components through named variables
* SSR (Server-Side Rendering) with React
* REST API integration with caching
* React Router v7 support for modern routing with SSR
* Promise handling for data loading during SSR
## Available Hooks
* **useRest(path, params, noThrow, cacheLifeTime)**: Fetches data from your backend with automatic caching and SSR support
* **useVar(varName, defaultValue)**: Provides shared state accessible by name throughout your application
* **useVarSetter(varName, defaultValue)**: Returns only a setter for the given variable without subscribing to updates
* **usePromise(promise)**: Registers a promise for SSR to wait for before rendering
* **useRestRefresh(path, params, cacheLifeTime)**: Returns only the refresh function for a REST endpoint
* **useRestResetter()**: Returns a function to clear all REST cache (useful for logout)
## Usage
### run(routes, promisesOrOptions, options)
The entry point function that replaces ReactDOM.render/hydrate with SSR support. Takes a route configuration and optional settings.
**Parameters:**
- `routes`: A React Router route configuration created with `createRoutesFromElements` or directly as a route object
- `promisesOrOptions`: Either an array of promises to wait for, or an options object
- `options`: Configuration options (when using promises as the second parameter)
**Options object properties:**
- `routerProps`: Additional props to pass to the Router component (useful for injecting stores or providers)
- `contextProps`: Additional props to pass to the internal Context.Provider
#### Basic usage in your `index.js`:
```javascript
import { run } from "@karpeleslab/react-klbfw-hooks";
import { Route, createRoutesFromElements } from "react-router-dom";
import Home from './routes/Home';
// Create routes with the Data Router API
const routes = createRoutesFromElements(
} />
);
// Pass the routes to run
run(routes);
```
#### Injecting additional props/providers:
```javascript
import { run } from "@karpeleslab/react-klbfw-hooks";
import { Route, createRoutesFromElements } from "react-router-dom";
import { Provider } from 'react-redux';
import { store } from './store';
import Home from './routes/Home';
// Create routes
const routes = createRoutesFromElements(
} />
);
// Inject the Redux store by providing custom router props
run(routes, {
routerProps: {
// These props will be passed to the RouterProvider (client) or StaticRouterProvider (server)
fallbackElement:
Loading...,
future: {
v7_startTransition: true
}
},
contextProps: {
// You can also wrap the entire app with providers using React.createElement in your index.js
// This is an alternative approach for global store/provider setup
}
});
```
#### With React Router v7:
```javascript
import { run } from "@karpeleslab/react-klbfw-hooks";
import { redirect, Route, createRoutesFromElements } from "react-router-dom";
import Home from './routes/Home';
import About from './routes/About';
import Contact from './routes/Contact';
// Create routes
const routes = createRoutesFromElements(
<>
} />
} />
}
loader={async () => {
// Load data needed for this route
const data = await fetch('/api/contact-info').then(r => r.json());
return data;
}}
/>
{
// Redirect example with status code
return redirect("/about", 301);
}}
/>
>
);
// Pass routes to run
run(routes);
```
### Server-Side Rendering with React Router v7
The library provides full support for React Router v7 SSR features including:
- **Data Loading**: Routes with loaders will have their data pre-loaded during SSR
- **Redirects**: Redirect responses from loaders are properly handled with status codes preserved
- **Data Router API**: Uses the modern React Router v7 data APIs (createBrowserRouter, createStaticHandler, createStaticRouter, RouterProvider, StaticRouterProvider)
Under the hood, the implementation:
1. On the client: Creates a browser router from routes using `createBrowserRouter`
2. On the server: Creates a static handler from routes using `createStaticHandler`
3. Processes routes with `query` function to detect redirects and load data
4. Renders using `createStaticRouter` and `StaticRouterProvider` for SSR
5. Preserves HTTP status codes (301, 302, etc.) for proper SEO
This allows you to use all modern React Router features while still benefiting from server-side rendering.
With i18n support:
```javascript
import { run } from "@karpeleslab/react-klbfw-hooks";
import { Route } from "react-router-dom";
import Home from './routes/Home';
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import { Backend } from '@karpeleslab/i18next-klb-backend';
import { getLocale } from "@karpeleslab/klbfw";
let i18nOpt = {
lng: getLocale(),
initImmediate: false,
load: 'currentOnly',
interpolation: {
escapeValue: false, // not needed for react as it escapes by default
},
react: {
useSuspense: false,
}
};
// Define your routes as an array of elements
const routes = [
} key="home" />
];
run(routes, [i18n.use(Backend).use(initReactI18next).init(i18nOpt)]);
```
### useVar(varName, defaultValue)
Hook for creating/accessing named variables which share a value anywhere in the application.
```javascript
function Counter() {
const [count, setCount] = useVar("counter", 0);
return (
Count is {count}
setCount(count + 1)}>Increment
);
}
```
In another component:
```javascript
function DisplayCounter() {
const [count] = useVar("counter", 0);
return
Current count: {count};
}
```
### useVarSetter(varName, defaultValue)
Returns only a setter for the given variable, without subscribing the current component to variable updates.
```javascript
function CounterControl() {
const setCount = useVarSetter("counter", 0);
return setCount(0)}>Reset Counter;
}
```
### usePromise(promise)
Registers a promise that the server needs to wait for in SSR before rendering. Useful for ensuring data is available during server-side rendering.
```javascript
function DataComponent() {
const [data, setData] = useState(null);
useEffect(() => {
const promise = fetchData().then(result => setData(result));
usePromise(promise);
}, []);
return
{data ? JSON.stringify(data) : "Loading..."};
}
```
### useRest(path, params, noThrow, cacheLifeTime)
Performs a REST GET request to the specified path, caching the result and returning it in a way that is safe for rendering.
```javascript
function UserProfile({ userId }) {
const [user, refreshUser] = useRest(`/api/users/${userId}`);
return (
{user ? (
<>
{user.name}
{user.email}
Refresh
>
) : "Loading..."}
);
}
```
With parameters:
```javascript
function SearchResults() {
const [query, setQuery] = useState("");
const [results, refreshResults] = useRest("/api/search", { q: query });
return (
setQuery(e.target.value)}
/>
Search
{results && results.map(item => (
{item.title}
))}
);
}
```
## License
MIT