A library of hooks that are useful with async code.

Last update: Jun 15, 2022

rxooks

GADZOOKS! RXOOKS!

(Basically every other iteration of "rxjs", "rx", "react", and "hooks" was taken)

This is a library of hooks that are useful with async code. Generally, these small, lightweight hooks are all you will need in most case.

What is this good for?

  1. async effects that are cancellable and give you values using:
  • promises (and async/await)
  • async iterators (async function*)
  • Observables! (obviously)
  1. creating updatable state that will give you something reactive, rather than firing a new render (ala useState)

  2. Dealing with any type that returns an "unsubscribable" { unsubscribe: () => void }, like an RxJS Subscription

Installation

npm i -S rxooks

Hooks

useAsyncValues

This is a hook that allows you to start an async effect that will self-cancel on dependency changes, pretty much like useEffect only it outputs a value, and you can use async function, async function* or any function that returns Promise, AsyncIterable, or Observable, (including things that implement Symbol.observable).

async functions

The code below will display "Loading..", and then "Hi!" after 2 seconds.

import { useAsyncValues } from 'rxooks';

function sleep(ms: number): Promise<void> {
	return new Promise((resolve) => setTimeout(resolve, ms));
}

export function MyComp() {
	const value = useAsyncValues(
		async function () {
			await sleep(2000);

			return 'Hi!';
		},
		[], // deps
		{ initialValue: 'Loading...' }
	);

	return <div>{value}</div>;
}

async iterables

The following creates a component that increments a counter once per second using an async generator.

import { useAsyncValues } from 'rxooks';

function sleep(ms: number): Promise<void> {
	return new Promise((resolve) => setTimeout(resolve, ms));
}

export function MyComp() {
	const value = useAsyncValues(
		async function* () {
			let n = 0;
			while (true) {
				yield n;
				await sleep(1000);
			}
		},
		[] // deps
	);

	return <div>Count: {value}</div>;
}

observables

The following creates a component that increments a counter once per second using an RxJS observable.

import { useAsyncValues } from 'rxooks';
import { interval } from 'rxjs';

export function MyComp() {
	const value = useAsyncValues(
		() => interval(1000),
		[] // deps
	);

	return <div>Count: {value}</div>;
}

useObservableState

This can be used to create a tuple of an observable of state changes, a setter to update the state, and a getter to get the state ad-hoc. Setting state with this hook will not cause a re-render. This hook is useful for when you want to wire a react event handler to an observable to build reactive flows.

Note that the returned observable will synchronously emit the current value on subscription. (Similar to a "BehaviorSubject" in RxJS, an "atom" in Recoil, or several other observable-like UI implementations folks use)

The setter allows the user to pass simple state updates, or they can pass a callback that gives them the previous state and returns the new state.

Using this is something that requires some knowledge of RxJS operators, generally. However it could be used without operators if you so choose.

Basic use

You might use useObservableState to do something like fetch data on a debounce.

Search
{hasSearchResults && (
    {searchResults.map((result) => (
  • {result.text}
  • ))}
)} ); }">
import { useObservableState, useAsyncValues } from 'rxooks';
import { debounceTime, swtichMap } from 'rxjs';

function MyComp() {
	// an observable of searches, and a setter to set the current search
	const [searches, setSearch, getSearch] = useObservableState('');

	// Here we're going to compose some reactivity using RxJS,
	// and subscribe to the observable to get the search results out.
	const searchResults = useAsyncValues(
		() =>
			searches.pipe(
				debounceTime(500),
				switchMap((search) => getSearchResults(search))
			),
		[searches] // deps
	);

	const searchResultCount = searchResults?.length ?? 0;
	const hasSearchResults = searchResultCount > 0;

	const searchChange = (e) => setSearch(e.target.value);

	// Maybe there's some other side effect you'd like to do with the
	// current value of the observable state. You can use the getter
	// for that.
	const submitForm = () => {
		// Use the getter to get the most recent value
		const lastSearch = getSearch();
		doSomethingOnFormSubmit(lastSearch);
	};

	return (
		<form onSubmit={submitForm}>
			<div>
				<label htmlFor="search-input">Search</label>
				<input id="search-input" type="text" onChange={searchChange} />
			</div>
			{hasSearchResults && (
				<ul>
					{searchResults.map((result) => (
						<li key={result.id}>{result.text}</li>
					))}
				</ul>
			)}
		</form>
	);
}

useSubscription

Simply put, this just allows you to create a side effect, like useEffect, only you return an Unsubscribable instead. That is, you return something of this shape: { unsubscribe: () => void } and useSubscriptoin will handle the setup and teardown based off of dependency changes, just like useEffect does.

This hook mostly exists to support useAsyncValues, however it's generally useful enough we're exporting it.

Primitive "subscription" example

Message: {message}
setPrefix(e.target.value)} />
); }">
import { useState } from 'react';
import { useSubscription } from 'rxooks';

export function MyComp() {
	const [prefix, setPrefix] = useState('Hello!');
	const [message, setMessage] = useState('');

	useSubscription(() => {
		let n = 0;
		const id = setInterval(() => setMessage(`${prefix} ${n++}`), 1000);
		return {
			unsubscribe: () => clearInterval(id),
		};
	}, [prefix]);

	return (
		<div>
			<div>
				<label htmlFor="message-display">Message:</label>
				<output id="message-display">{message}</output>
			</div>
			<div>
				<label htmlFor="prefix-input">Message Prefix:</label>
				<input
					id="prefix-input"
					type="text"
					value={prefix}
					onChange={(e) => setPrefix(e.target.value)}
				/>
			</div>
		</div>
	);
}

RxJS Subscription example

Maybe you want to set up some effect that doesn't update your view, but uses a subscription. You can use this hook to set up and RxJS subscription that runs and does just that (unlike useAsyncValues, which will emit a value that triggers a render).

import { useSubscription } from 'rxooks';
import { interval } from 'rxjs';

export function MyComp() {
	useSubscription(
		() =>
			interval(1000).subscribe((n) => {
				console.log(`Tick ${n}`);
			}),
		[]
	);

	return <div>I'm logging in the background</div>;
}

GitHub

https://github.com/benlesh/rxooks
You might also like...

Sending HTTP GET request and handing the response in React Js by async await.

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: np

Dec 22, 2021

React hook to execute and watch async function

react-async-watcher React hook to execute and watch async function Introduction This package is made for handle asynchronous tasks, such as backend ap

Apr 15, 2021

😎📋 React hooks for forms state and validation, less code more performant.

React hooks for forms state and validation, less code more performant. Features đŸŽŖ Easy to use, just a React hook. 🗃 Manages complex form data withou

Jun 23, 2022

React hooks for generating QR code for your next React apps.

React hooks for generating QR code for your next React apps.

Jun 16, 2022

🍹 A lot of nice hooks to make react hooks easier to use ( useState callback / life cycle / instance variable)

🍹 Nice Hooks 中文į‰ˆ A lot of nice hooks to make react hooks easier to use. If you find this project is useful to you, please give me a star. Installatio

May 5, 2022

Learn the more advanced React hooks and different patterns to enable great developer APIs for custom hooks

Learn the more advanced React hooks and different patterns to enable great developer APIs for custom hooks

đŸ”Ĩ Advanced React Hooks 🚀 EpicReact.Dev Learn the more advanced React hooks and different patterns to enable great developer APIs for custom hooks. W

Mar 15, 2022

ReactJs Custom hooks, component lifecycle - Indispensable hooks

ReactJs Custom hooks, component lifecycle - Indispensable hooks

Jun 16, 2022

React Hooks Library

React Hooks Library

English | įŽ€äŊ“中文 ahooks React Hooks Library. 📚 Documentation English 中文 ✨ Features Easy to learn and use. Contains a wealth of advanced Hooks that are

Jun 21, 2022

React Hooks library for element visibility. Uses the intersection observer API.

react-hooks-visible react-hooks-visible is React Hooks library for element visibility. Uses the intersection observer API. demo Get started yarn add r

Nov 15, 2021
Comments
  • 1. chore: move react to peerDependencies

    Hey Ben, thanks for this library. I've been using it for a bit and it seems to work great!

    When updating my React version to 18.2.0 I ran into an error about having 2 React versions in my app and it looks like library authors need to add it to peerDependencies to prevent this from happing.

    image

    By the way, it looks like the whole package-lock.json got formatted, so you might want to run an npm i locally to ensure it's created with the same npm version.

    Reviewed by beeman at 2022-06-18 00:55
  • 2. small typo

    import { debounceTime, swtichMap } from 'rxjs'; - in useObservableState

    and a question: Where does "getSearchResults(search)" come from? import { useObservableState, useAsyncValues } from 'rxooks'; import { debounceTime, swtichMap } from 'rxjs';

    function MyComp() { // an observable of searches, and a setter to set the current search const [searches, setSearch, getSearch] = useObservableState('');

    // Here we're going to compose some reactivity using RxJS,
    // and subscribe to the observable to get the search results out.
    const searchResults = useAsyncValues(
    	() =>
    		searches.pipe(
    			debounceTime(500),
    			switchMap((search) => **getSearchResults(search))**
    		),
    	[searches] // deps
    );
    
    const searchResultCount = searchResults?.length ?? 0;
    const hasSearchResults = searchResultCount > 0;
    
    const searchChange = (e) => setSearch(e.target.value);
    
    // Maybe there's some other side effect you'd like to do with the
    // current value of the observable state. You can use the getter
    // for that.
    const submitForm = () => {
    	// Use the getter to get the most recent value
    	const lastSearch = getSearch();
    	doSomethingOnFormSubmit(lastSearch);
    };
    
    return (
    	<form onSubmit={submitForm}>
    		<div>
    			<label htmlFor="search-input">Search</label>
    			<input id="search-input" type="text" onChange={searchChange} />
    		</div>
    		{hasSearchResults && (
    			<ul>
    				{searchResults.map((result) => (
    					<li key={result.id}>{result.text}</li>
    				))}
    			</ul>
    		)}
    	</form>
    );
    

    }

    Reviewed by hansschenker at 2022-06-06 08:02
A collection of useful React hooks

??‍♂ī¸ Made by @thekitze, improved by @rip212 Other projects: ?? React Academy - Interactive React and GraphQL workshops ?? Twizzy - A standalone app f

Jun 17, 2022
:alien: A collection of useful React hooks
:alien: A collection of useful React hooks

Hooks require at least React 16.8 Installation using npm npm install react-hookedup --save using yarn yarn add react-hookedup Demo Visit here hooks

May 31, 2022
A small package of custom React hooks that are useful for debugging changes in React hook dependencies across renders

use-debugger-hooks This is a package of custom React hooks that are useful for debugging dependency changes between renders. Most act as drop in repla

Jun 10, 2022
React useful hooks.

Welcome to react-useful-hooks ?? react-useful-hooks. ?? Homepage Install yarn install Run tests yarn yarn dev Run build yarn yarn build Run lint yar

Jan 8, 2022
React custom hooks for async functions with abortability and composability
React custom hooks for async functions with abortability and composability

react-hooks-async React custom hooks for async functions with abortability and composability Introduction JavaScript promises are not abortable/cancel

Apr 28, 2022
👩‍đŸŗ A React Hooks utility library containing popular customized hooks
👩‍đŸŗ A React Hooks utility library containing popular customized hooks

React Recipes A React Hooks utility library containing popular customized hooks What's your favorite dish? npm i react-recipes --save yarn add react-r

Jun 16, 2022
React hook to handle any async operation in React components, and prevent race conditions

React-async-hook This library only does one small thing, and does it well. Don't expect it to grow in size, because it is feature complete: Handle fet

Jun 25, 2022
Async HTTP request data for axios. Designed for diverse UI states, SSR and data pre-caching.

React useApi() Axios-based React hooks for async HTTP request data. react-use-api feeds API data to React components when SSR (Server-Side Rendering),

May 26, 2022
React hook for generating async memoized data.

useAsyncMemo React hook for generating async memoized data. API function useAsyncMemo<T>(factory: () => Promise<T>, deps: DependencyList, initial?: T)

Jun 14, 2022
React useReducer with async actions

use-reducer-async React useReducer with async actions Introduction React useReducer doesn't support async actions natively. Unlike Redux, there's no m

Jun 22, 2022