Skip to content

KarpelesLab/react-klbfw-hooks

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

48 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

React Hooks for KLBFW

A collection of React hooks and SSR utilities for KarpelesLab Framework.

Installation

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:

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(
  <Route path="/" element={<Home />} />
);

// Pass the routes to run
run(routes);

Injecting additional props/providers:

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(
  <Route path="/" element={<Home />} />
);

// 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: <div>Loading...</div>,
    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:

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(
  <>
    <Route path="/" element={<Home />} />
    <Route path="/about" element={<About />} />
    <Route 
      path="/contact" 
      element={<Contact />} 
      loader={async () => {
        // Load data needed for this route
        const data = await fetch('/api/contact-info').then(r => r.json());
        return data;
      }}
    />
    <Route 
      path="/redirect" 
      loader={() => {
        // 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:

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 <Route> elements
const routes = [
  <Route path="/" element={<Home />} 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.

function Counter() {
	const [count, setCount] = useVar("counter", 0);

	return (
		<div>
			Count is {count}
			<button onClick={() => setCount(count + 1)}>Increment</button>
		</div>
	);
}

In another component:

function DisplayCounter() {
	const [count] = useVar("counter", 0);
	return <div>Current count: {count}</div>;
}

useVarSetter(varName, defaultValue)

Returns only a setter for the given variable, without subscribing the current component to variable updates.

function CounterControl() {
	const setCount = useVarSetter("counter", 0);
	return <button onClick={() => setCount(0)}>Reset Counter</button>;
}

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.

function DataComponent() {
	const [data, setData] = useState(null);
	
	useEffect(() => {
		const promise = fetchData().then(result => setData(result));
		usePromise(promise);
	}, []);
	
	return <div>{data ? JSON.stringify(data) : "Loading..."}</div>;
}

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.

function UserProfile({ userId }) {
	const [user, refreshUser] = useRest(`/api/users/${userId}`);
	
	return (
		<div>
			{user ? (
				<>
					<h2>{user.name}</h2>
					<p>{user.email}</p>
					<button onClick={refreshUser}>Refresh</button>
				</>
			) : "Loading..."}
		</div>
	);
}

With parameters:

function SearchResults() {
	const [query, setQuery] = useState("");
	const [results, refreshResults] = useRest("/api/search", { q: query });
	
	return (
		<div>
			<input 
				value={query} 
				onChange={e => setQuery(e.target.value)} 
			/>
			<button onClick={refreshResults}>Search</button>
			
			{results && results.map(item => (
				<div key={item.id}>{item.title}</div>
			))}
		</div>
	);
}

License

MIT

About

GET Hooks for klbfw

Resources

Stars

Watchers

Forks

Packages

No packages published

Contributors 3

  •  
  •  
  •