Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/leetcode-opensource/rxjs-hooks
React hooks for RxJS
https://github.com/leetcode-opensource/rxjs-hooks
observable react react-hooks rxjs rxjs6
Last synced: 6 days ago
JSON representation
React hooks for RxJS
- Host: GitHub
- URL: https://github.com/leetcode-opensource/rxjs-hooks
- Owner: LeetCode-OpenSource
- Created: 2018-11-15T08:18:54.000Z (about 6 years ago)
- Default Branch: master
- Last Pushed: 2023-04-07T09:44:29.000Z (almost 2 years ago)
- Last Synced: 2025-01-04T16:01:56.683Z (14 days ago)
- Topics: observable, react, react-hooks, rxjs, rxjs6
- Language: TypeScript
- Size: 4.93 MB
- Stars: 2,187
- Watchers: 27
- Forks: 84
- Open Issues: 21
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# React hooks for RxJS
[![CircleCI](https://circleci.com/gh/LeetCode-OpenSource/rxjs-hooks.svg?style=svg)](https://circleci.com/gh/LeetCode-OpenSource/rxjs-hooks)
[![codecov](https://codecov.io/gh/LeetCode-OpenSource/rxjs-hooks/branch/master/graph/badge.svg)](https://codecov.io/gh/LeetCode-OpenSource/rxjs-hooks)
[![npm version](https://badge.fury.io/js/rxjs-hooks.svg)](https://badge.fury.io/js/rxjs-hooks)- [Installation](#installation)
- [Demo](#quick-look)
- [Apis](#apis)
1. [useObservable](#useobservable)
2. [useEventCallback](#useeventcallback)## Installation
Using npm:
```
$ npm i --save rxjs-hooks rxjs
```Or yarn:
```
$ yarn add rxjs-hooks rxjs
```## Quick look
- [useObservable - live demo](https://codesandbox.io/s/rxjs-hooks-basic-oee81n)
```javascript
import React from "react";
import ReactDOM from "react-dom/client";
import { useObservable } from "rxjs-hooks";
import { interval } from "rxjs";
import { map } from "rxjs/operators";function App() {
const value = useObservable(() => interval(500).pipe(map((val) => val * 3)));return (
Incremental number: {value}
);
}
```- [useEventCallback - live demo](https://codesandbox.io/s/rxjs-hooks-useeventcallback-forked-5s1mvq)
```javascript
import React from "react";
import ReactDOM from "react-dom/client";
import { useEventCallback } from "rxjs-hooks";
import { map } from "rxjs/operators";function App() {
const [clickCallback, [description, x, y]] = useEventCallback((event$) =>
event$.pipe(
map((event) => [event.target.innerHTML, event.clientX, event.clientY]),
),
["nothing", 0, 0],
)return (
click position: {x}, {y}
"{description}" was clicked.
click me
click you
click him
);
}
```## Apis
### `useObservable`
```tsx
export type InputFactory = (state$: Observable) => Observable
export type InputFactoryWithInputs = (
state$: Observable,
inputs$: Observable>,
) => Observableexport function useObservable(inputFactory: InputFactory): State | null
export function useObservable(inputFactory: InputFactory, initialState: State): State
export function useObservable(
inputFactory: InputFactoryWithInputs,
initialState: State,
inputs: RestrictArray,
): State
```#### Examples:
```tsx
import React from 'react'
import ReactDOM from 'react-dom'
import { useObservable } from 'rxjs-hooks'
import { of } from 'rxjs'function App() {
const value = useObservable(() => of(1000))
return (
// render twice
// null and 1000
{value}
)
}
```**With default value:**
```tsx
import React from 'react'
import ReactDOM from 'react-dom'
import { useObservable } from 'rxjs-hooks'
import { of } from 'rxjs'function App() {
const value = useObservable(() => of(1000), 200)
return (
// render twice
// 200 and 1000
{value}
)
}
```**Observe props change:**
```tsx
import React from 'react'
import ReactDOM from 'react-dom'
import { useObservable } from 'rxjs-hooks'
import { map } from 'rxjs/operators'function App(props: { foo: number }) {
const value = useObservable((_, inputs$) => inputs$.pipe(
map(([val]) => val + 1),
), 200, [props.foo])
return (
// render three times
// 200 and 1001 and 2001
{value}
)
}
const rootElement = document.querySelector("#app");
ReactDOM.createRoot(rootElement).render();
ReactDOM.createRoot(rootElement).render();
```**useObservable with state$**
[live demo](https://codesandbox.io/s/rxjs-hooks-useobservable-with-state-forked-9fjefy)
```tsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import { useObservable } from 'rxjs-hooks'
import { interval } from 'rxjs'
import { map, withLatestFrom } from 'rxjs/operators'function App() {
const value = useObservable((state$) => interval(1000).pipe(
withLatestFrom(state$),
map(([_num, state]) => state * state),
), 2)
return (
// 2
// 4
// 16
// 256
// ...
{value}
)
}
```### `useEventCallback`
#### Examples:
```tsx
import React from 'react'
import ReactDOM from 'react-dom'
import { useEventCallback } from 'rxjs-hooks'
import { mapTo } from 'rxjs/operators'function App() {
const [clickCallback, value] = useEventCallback((event$: Observable>) =>
event$.pipe(
mapTo(1000)
)
)
return (
// render null
// click button
// render 1000
<>
{value}
click me
>
)
}```
**With initial value:**
```tsx
import React from 'react'
import ReactDOM from 'react-dom'
import { useEventCallback } from 'rxjs-hooks'
import { mapTo } from 'rxjs/operators'function App() {
const [clickCallback, value] = useEventCallback((event$: Observable>) =>
event$.pipe(
mapTo(1000)
),
200,
)
return (
// render 200
// click button
// render 1000
<>
{value}
click me
>
)
}```
**With state$:**
[live demo](https://codesandbox.io/s/rxjs-hooks-useeventcallback-with-state-forked-rg1frx)
```tsx
import React from "react";
import ReactDOM from "react-dom/client";
import { useEventCallback } from "rxjs-hooks";
import { map, withLatestFrom } from "rxjs/operators";function App() {
const [clickCallback, [description, x, y, prevDescription]] = useEventCallback(
(event$, state$) =>
event$.pipe(
withLatestFrom(state$),
map(([event, state]) => [
event.target.innerHTML,
event.clientX,
event.clientY,
state[0],
])
),
["nothing", 0, 0, "nothing"]
);return (
click position: {x}, {y}
"{description}" was clicked.
"{prevDescription}" was clicked previously.
click me
click you
click him
);
}```
**A complex example: useEventCallback with both `inputs$` and `state$`**
[live demo](https://codesandbox.io/s/rxjs-hooks-useeventcallback-with-state-forked-tlwdil)
```tsx
import React, { useState } from "react";
import ReactDOM from "react-dom";
import { useEventCallback } from "rxjs-hooks";
import { map, withLatestFrom, combineLatest } from "rxjs/operators";import "./styles.css";
function App() {
const [count, setCount] = useState(0);
const [clickCallback, [description, x, y, prevDesc]] = useEventCallback(
(event$, state$, inputs$) =>
event$.pipe(
map(event => [event.target.innerHTML, event.clientX, event.clientY]),
combineLatest(inputs$),
withLatestFrom(state$),
map(([eventAndInput, state]) => {
const [[text, x, y], [count]] = eventAndInput;
const prevDescription = state[0];
return [text, x + count, y + count, prevDescription];
})
),
["nothing", 0, 0, "nothing"],
[count]
);return (
click position: {x}, {y}
"{description}" was clicked.
"{prevDesc}" was clicked previously.
click me
click you
click him
click buttons above, and then click this `+++` button, the position
numbers will grow.
setCount(count + 1)}>+++
);
}```
**Example of combining callback observables coming from separate elements - animation with start/stop button and rate controllable via slider**
[live demo](https://codesandbox.io/s/late-wood-x5rg0l)
```tsx
const Animation = ({ frame }) => {
const frames = "|/-\\|/-\\|".split("");
return (
{frames[frame % frames.length]}
);
};const App = () => {
const defaultRate = 5;const [running, setRunning] = useState(false);
const [onEvent, frame] = useEventCallback(events$ => {
const running$ = events$.pipe(
filter(e => e.type === "click"),
scan(running => !running, running),
startWith(running),
tap(setRunning)
);return events$.pipe(
filter(e => e.type === "change"),
map(e => parseInt(e.target.value, 10)),
startWith(defaultRate),
switchMap(i => timer(200, 1000 / i)),
withLatestFrom(running$),
filter(([_, running]) => running),
scan(frame => frame + 1, 0)
);
});return (
{running ? "Stop" : "Start"}
);
};
```## Known issues
If you are using React 18 + `StrictMode` under NODE_ENV=development, `rxjs-hooks` may not work properly. https://github.com/facebook/react/issues/24502#issuecomment-1118846544