mirror of
https://github.com/re-rxjs/react-rxjs.git
synced 2025-12-08 18:01:51 +00:00
chore: READMEs point to the website
This commit is contained in:
parent
023fd82d45
commit
9ad463f13b
245
README.md
245
README.md
@ -1,4 +1,4 @@
|
||||
# <img height="86" width="86" alt="React-RxJS Logo" src="assets/logo-128.png" /> React-RxJS: React bindings for RxJS
|
||||
# <img height="86" width="86" alt="React-RxJS Logo" src="assets/logo-128.png" /> React-RxJS
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
[](https://github.com/re-rxjs/react-rxjs/actions)
|
||||
@ -10,6 +10,10 @@
|
||||
[](https://github.com/re-rxjs/react-rxjs/blob/main/CODE_OF_CONDUCT.md)
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
React-RxJS is a library that offers [React](https://reactjs.org/) bindings for [RxJS](https://rxjs.dev/)
|
||||
|
||||
Please visit the website: https://react-rxjs.org
|
||||
|
||||
## Main features
|
||||
|
||||
- :cyclone: Truly Reactive
|
||||
@ -19,249 +23,10 @@
|
||||
- :microscope: [Tiny and tree-shakeable](https://bundlephobia.com/result?p=react-rxjs)
|
||||
- :muscle: Supports TypeScript
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Installation](#installation)
|
||||
- [API](#api)
|
||||
- Core
|
||||
- [bind](#bind)
|
||||
- [Observable overload](#observable-overload)
|
||||
- [Factory of Observables overload](#factory-of-observables-overload)
|
||||
- [shareLatest](#sharelatest)
|
||||
- [SUSPENSE](#suspense)
|
||||
- [useSubscribe](#usesubscribe)
|
||||
- [Subscribe](#subscribe)
|
||||
- [Examples](#examples)
|
||||
|
||||
## Installation
|
||||
|
||||
npm install @react-rxjs/core
|
||||
|
||||
## API
|
||||
|
||||
### bind
|
||||
|
||||
#### Observable overload
|
||||
|
||||
```ts
|
||||
const [useCounter, sharedCounter$] = bind(
|
||||
clicks$.pipe(
|
||||
scan((prev) => prev + 1, 0),
|
||||
startWith(0),
|
||||
),
|
||||
)
|
||||
```
|
||||
|
||||
Accepts: An Observable.
|
||||
|
||||
Returns `[1, 2]`
|
||||
|
||||
1. A React Hook that yields the latest emitted value of the observable. If the
|
||||
Observable doesn't synchronously emit a value upon the first subscription, then
|
||||
the hook will leverage React Suspense while it's waiting for the first value.
|
||||
|
||||
2. A `sharedLatest` version of the observable. It can be used for composing other
|
||||
streams that depend on it. The shared subscription is closed as soon as there
|
||||
are no subscribers to that observable.
|
||||
|
||||
#### Factory of Observables overload
|
||||
|
||||
```tsx
|
||||
const [useStory, getStory$] = bind((storyId: number) =>
|
||||
getStoryWithUpdates$(storyId),
|
||||
)
|
||||
|
||||
const Story: React.FC<{ id: number }> = ({ id }) => {
|
||||
const story = useStory(id)
|
||||
|
||||
return (
|
||||
<article>
|
||||
<h1>{story.title}</h1>
|
||||
<p>{story.description}</p>
|
||||
</article>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
Accepts: A factory function that returns an Observable.
|
||||
|
||||
Returns `[1, 2]`
|
||||
|
||||
1. A React Hook function with the same parameters as the factory function. This hook
|
||||
will yield the latest update from the observable returned from the factory function.
|
||||
If the Observable doesn't synchronously emit a value upon the first subscription, then
|
||||
the hook will leverage React Suspense while it's waiting for the first value.
|
||||
|
||||
2. A `sharedLatest` version of the observable returned by the factory function. It
|
||||
can be used for composing other streams that depend on it. The shared subscription
|
||||
is closed as soon as there are no subscribers to that observable.
|
||||
|
||||
### shareLatest
|
||||
|
||||
```ts
|
||||
const activePlanetName$ = planet$.pipe(
|
||||
filter((planet) => planet.isActive),
|
||||
map((planet) => planet.name),
|
||||
shareLatest(),
|
||||
)
|
||||
```
|
||||
|
||||
A RxJS pipeable operator which shares and replays the latest emitted value. It's
|
||||
the equivalent of:
|
||||
|
||||
```ts
|
||||
const shareLatest = <T>(): Observable<T> =>
|
||||
source$.pipe(
|
||||
multicast(() => new ReplaySubject<T>(1)),
|
||||
refCount(),
|
||||
)
|
||||
```
|
||||
|
||||
The enhanced observables returned from `bind` have been enhanced with this operator.
|
||||
|
||||
### SUSPENSE
|
||||
|
||||
```ts
|
||||
const story$ = selectedStoryId$.pipe(
|
||||
switchMap((id) => concat(SUSPENSE, getStory$(id))),
|
||||
)
|
||||
```
|
||||
|
||||
This is a special symbol that can be emitted from our observables to let the react hook
|
||||
know that there is a value on its way, and that we want to leverage React Suspense
|
||||
while we are waiting for that value.
|
||||
|
||||
### useSubscribe
|
||||
|
||||
A React hook that creates a subscription to the provided observable once the
|
||||
component mounts and it unsubscribes when the component unmounts.
|
||||
|
||||
Arguments:
|
||||
|
||||
- `source$`: Source observable that the hook will subscribe to.
|
||||
|
||||
Important: This hook doesn't trigger any updates.
|
||||
|
||||
### Subscribe
|
||||
|
||||
A React Component that creates a subscription to the provided observable once
|
||||
the component mounts and it unsubscribes from it when the component unmounts.
|
||||
|
||||
Properties:
|
||||
|
||||
- `source$`: Source observable that the Component will subscribe to.
|
||||
- `fallback?`: The JSX Element to be rendered before the subscription is created.
|
||||
It defaults to `null`.
|
||||
|
||||
Important: This Component doesn't trigger any updates.
|
||||
|
||||
## Examples
|
||||
|
||||
- [This is a contrived example](https://codesandbox.io/s/crazy-wood-vn7gg?file=/src/fakeApi.js) based on [this example](https://reactjs.org/docs/concurrent-mode-patterns.html#reviewing-the-changes) from the React docs.
|
||||
|
||||
- A search for Github repos that highlights the most recently updated one:
|
||||
|
||||
```tsx
|
||||
import React, { Suspense } from "react"
|
||||
import { Subject } from "rxjs"
|
||||
import { startWith, map } from "rxjs/operators"
|
||||
import { bind } from "@react-rxjs/core"
|
||||
import { switchMapSuspended } from "@react-rxjs/utils"
|
||||
import { Header, Search, LoadingResults, Repo } from "./components"
|
||||
|
||||
interface Repo {
|
||||
id: number
|
||||
name: string
|
||||
description: string
|
||||
author: string
|
||||
stars: number
|
||||
lastUpdate: number
|
||||
}
|
||||
|
||||
const searchInput$ = new Subject<string>()
|
||||
const onSubmit = (value: string) => searchInput$.next(value)
|
||||
|
||||
const findRepos = (query: string): Promise<Repo[]> =>
|
||||
fetch(`https://api.github.com/search/repositories?q=${query}`)
|
||||
.then((response) => response.json())
|
||||
.then((rawData) =>
|
||||
(rawData.items ?? []).map((repo: any) => ({
|
||||
id: repo.id,
|
||||
name: repo.name,
|
||||
description: repo.description,
|
||||
author: repo.owner.login,
|
||||
stars: repo.stargazers_count,
|
||||
lastUpdate: Date.parse(repo.update_at),
|
||||
})),
|
||||
)
|
||||
|
||||
const [useRepos, repos$] = bind(
|
||||
searchInput$.pipe(switchMapSuspended(findRepos), startWith(null)),
|
||||
)
|
||||
|
||||
function Repos() {
|
||||
const repos = useRepos()
|
||||
|
||||
if (repos === null) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (repos.length === 0) {
|
||||
return <p>No results were found.</p>
|
||||
}
|
||||
|
||||
return (
|
||||
<ul>
|
||||
{repos.map((repo) => (
|
||||
<li key={repo.id}>
|
||||
<Repo {...repo} />
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)
|
||||
}
|
||||
|
||||
const [useMostRecentlyUpdatedRepo] = bind(
|
||||
repos$.pipe(
|
||||
map((repos) =>
|
||||
Array.isArray(repos) && repos.length > 0
|
||||
? repos.reduce((winner, current) =>
|
||||
current.lastUpdate > winner.lastUpdate ? current : winner,
|
||||
)
|
||||
: null,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
function MostRecentlyUpdatedRepo() {
|
||||
const mostRecent = useMostRecentlyUpdatedRepo()
|
||||
|
||||
if (mostRecent === null) {
|
||||
return null
|
||||
}
|
||||
|
||||
const { id, name } = mostRecent
|
||||
return (
|
||||
<p>
|
||||
The most recently updated repo is <a href={`#${id}`}>{name}</a>
|
||||
</p>
|
||||
)
|
||||
}
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<>
|
||||
<Header>Search Github Repos</Header>
|
||||
<Search onSubmit={onSubmit} />
|
||||
<Suspense fallback={<LoadingResults />}>
|
||||
<MostRecentlyUpdatedRepo />
|
||||
<Repos />
|
||||
</Suspense>
|
||||
</>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
## Contributors ✨
|
||||
|
||||
Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
|
||||
|
||||
@ -1,123 +1,7 @@
|
||||
# @react-rxjs/core
|
||||
|
||||
Please visit the website: https://react-rxjs.org
|
||||
|
||||
## Installation
|
||||
|
||||
npm install @react-rxjs/core
|
||||
|
||||
## API
|
||||
|
||||
### bind
|
||||
|
||||
#### Observable overload
|
||||
|
||||
```ts
|
||||
const [useCounter, sharedCounter$] = bind(
|
||||
clicks$.pipe(
|
||||
scan((prev) => prev + 1, 0),
|
||||
startWith(0),
|
||||
),
|
||||
)
|
||||
```
|
||||
|
||||
Accepts: An Observable.
|
||||
|
||||
Returns `[1, 2]`
|
||||
|
||||
1. A React Hook that yields the latest emitted value of the observable. If the
|
||||
Observable doesn't synchronously emit a value upon the first subscription, then
|
||||
the hook will leverage React Suspense while it's waiting for the first value.
|
||||
|
||||
2. A `sharedLatest` version of the observable. It can be used for composing other
|
||||
streams that depend on it. The shared subscription is closed as soon as there
|
||||
are no subscribers to that observable.
|
||||
|
||||
#### Factory Observables overload
|
||||
|
||||
```tsx
|
||||
const [useStory, getStory$] = bind((storyId: number) =>
|
||||
getStoryWithUpdates$(storyId),
|
||||
)
|
||||
|
||||
const Story: React.FC<{ id: number }> = ({ id }) => {
|
||||
const story = useStory(id)
|
||||
|
||||
return (
|
||||
<article>
|
||||
<h1>{story.title}</h1>
|
||||
<p>{story.description}</p>
|
||||
</article>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
Accepts: A factory function that returns an Observable.
|
||||
|
||||
Returns `[1, 2]`
|
||||
|
||||
1. A React Hook function with the same parameters as the factory function. This hook
|
||||
will yield the latest update from the observable returned from the factory function.
|
||||
If the Observable doesn't synchronously emit a value upon the first subscription, then
|
||||
the hook will leverage React Suspense while it's waiting for the first value.
|
||||
|
||||
2. A `sharedLatest` version of the observable returned by the factory function. It
|
||||
can be used for composing other streams that depend on it. The shared subscription
|
||||
is closed as soon as there are no subscribers to that observable.
|
||||
|
||||
### shareLatest
|
||||
|
||||
```ts
|
||||
const activePlanetName$ = planet$.pipe(
|
||||
filter((planet) => planet.isActive),
|
||||
map((planet) => planet.name),
|
||||
shareLatest(),
|
||||
)
|
||||
```
|
||||
|
||||
A RxJS pipeable operator which shares and replays the latest emitted value. It's
|
||||
the equivalent of:
|
||||
|
||||
```ts
|
||||
const shareLatest = <T>(): Observable<T> =>
|
||||
source$.pipe(
|
||||
multicast(() => new ReplaySubject<T>(1)),
|
||||
refCount(),
|
||||
)
|
||||
```
|
||||
|
||||
The enhanced observables returned from `bind` have been enhanced with this operator.
|
||||
|
||||
### SUSPENSE
|
||||
|
||||
```ts
|
||||
const story$ = selectedStoryId$.pipe(
|
||||
switchMap((id) => concat(SUSPENSE, getStory$(id))),
|
||||
)
|
||||
```
|
||||
|
||||
This is a special symbol that can be emitted from our observables to let the react hook
|
||||
know that there is a value on its way, and that we want to leverage React Suspense
|
||||
while we are waiting for that value.
|
||||
|
||||
### useSubscribe
|
||||
|
||||
A React hook that creates a subscription to the provided observable once the
|
||||
component mounts and it unsubscribes when the component unmounts.
|
||||
|
||||
Arguments:
|
||||
|
||||
- `source$`: Source observable that the hook will subscribe to.
|
||||
|
||||
Important: This hook doesn't trigger any updates.
|
||||
|
||||
### Subscribe
|
||||
|
||||
A React Component that creates a subscription to the provided observable once
|
||||
the component mounts and it unsubscribes from it when the component unmounts.
|
||||
|
||||
Properties:
|
||||
|
||||
- `source$`: Source observable that the Component will subscribe to.
|
||||
- `fallback?`: The JSX Element to be rendered before the subscription is created.
|
||||
It defaults to `null`.
|
||||
|
||||
Important: This Component doesn't trigger any updates.
|
||||
|
||||
@ -1,23 +1,7 @@
|
||||
# @react-rxjs/dom
|
||||
|
||||
Please visit the website: https://react-rxjs.org
|
||||
|
||||
## Installation
|
||||
|
||||
npm install @react-rxjs/dom
|
||||
|
||||
## API
|
||||
|
||||
### batchUpdates
|
||||
|
||||
A RxJS pipeable operator which observes the source observable on
|
||||
an asapScheduler and uses `ReactDom.unstable_batchedUpdates` to emit the
|
||||
values. It's useful for observing streams of events that come from outside
|
||||
of ReactDom event-handlers.
|
||||
|
||||
IMPORTANT: This operator will be deprecated when React 17 is released
|
||||
(or whenever React CM is released). The reason being that React Concurrent Mode
|
||||
automatically batches all synchronous updates. Meaning that with React CM,
|
||||
observing a stream through the asapScheduler accomplishes the same thing.
|
||||
|
||||
```ts
|
||||
const marketUpdates$ = defer(() => api.getMarketUpdates()).pipe(batchUpdates())
|
||||
```
|
||||
|
||||
@ -1,172 +1,7 @@
|
||||
# @react-rxjs/utils
|
||||
|
||||
Please visit the website: https://react-rxjs.org
|
||||
|
||||
## Installation
|
||||
|
||||
npm install @react-rxjs/utils
|
||||
|
||||
## API
|
||||
|
||||
### split
|
||||
|
||||
A RxJS operator that groups the items emitted by the source based on the
|
||||
keySelector function, emitting one Observable for each group.
|
||||
|
||||
Arguments:
|
||||
|
||||
- `keySelector`: A function that receives an item and returns the key of that
|
||||
item's group.
|
||||
- `streamSelector`: (optional) The function to apply to each group observable
|
||||
(default = identity).
|
||||
|
||||
`split` will subscribe to each group observable and share the result to every
|
||||
inner subscriber of that group. This inner observable can be mapped to another
|
||||
observable through the `streamSelector` argument.
|
||||
|
||||
### collectValues
|
||||
|
||||
A pipeable operator that collects all the GroupedObservables emitted by
|
||||
the source and emits a Map with the latest values of the inner observables.
|
||||
|
||||
```ts
|
||||
const votesByKey$ = new Subject<{ key: string }>()
|
||||
const counters$ = votesByKey$.pipe(
|
||||
split(
|
||||
(vote) => vote.key,
|
||||
(votes$) =>
|
||||
votes$.pipe(
|
||||
mapTo(1),
|
||||
scan((count) => count + 1),
|
||||
takeWhile((count) => count < 3),
|
||||
),
|
||||
),
|
||||
collectValues(),
|
||||
)
|
||||
|
||||
counters$.subscribe((counters) => {
|
||||
console.log("counters$:")
|
||||
counters.forEach((value, key) => {
|
||||
console.log(`${key}: ${value}`)
|
||||
})
|
||||
})
|
||||
|
||||
votesByKey$.next({ key: "foo" })
|
||||
// > counters$:
|
||||
// > foo: 1
|
||||
|
||||
votesByKey$.next({ key: "foo" })
|
||||
// > counters$:
|
||||
// > foo: 2
|
||||
|
||||
votesByKey$.next({ key: "bar" })
|
||||
// > counters$:
|
||||
// > foo: 2
|
||||
// > bar: 1
|
||||
|
||||
votesByKey$.next({ key: "foo" })
|
||||
// > counters$:
|
||||
// > bar: 1
|
||||
|
||||
votesByKey$.next({ key: "bar" })
|
||||
// > counters$:
|
||||
// > bar: 2
|
||||
//
|
||||
votesByKey$.next({ key: "bar" })
|
||||
// > counters$:
|
||||
```
|
||||
|
||||
### collect
|
||||
|
||||
A pipeable operator that collects all the GroupedObservables emitted by
|
||||
the source and emits a Map with the active inner observables.
|
||||
|
||||
Arguments:
|
||||
|
||||
- `filter?`: A function that receives the inner Observable and returns an
|
||||
Observable of boolean values, which indicates whether the inner observable
|
||||
should be collected.
|
||||
|
||||
### mergeWithKey
|
||||
|
||||
Emits the values from all the streams of the provided object, in a result
|
||||
which provides the key of the stream of that emission.
|
||||
|
||||
Arguments:
|
||||
|
||||
- `inputObject`: Object of streams
|
||||
|
||||
```ts
|
||||
const inc$ = new Subject()
|
||||
const dec$ = new Subject()
|
||||
const resetTo$ = new Subject<number>()
|
||||
|
||||
const counter$ = mergeWithKey({
|
||||
inc$,
|
||||
dec$,
|
||||
resetTo$,
|
||||
}).pipe(
|
||||
scan((acc, current) => {
|
||||
switch (current.type) {
|
||||
case "inc$":
|
||||
return acc + 1
|
||||
case "dec$":
|
||||
return acc - 1
|
||||
case "resetTo$":
|
||||
return current.payload
|
||||
default:
|
||||
return acc
|
||||
}
|
||||
}, 0),
|
||||
startWith(0),
|
||||
)
|
||||
```
|
||||
|
||||
### selfDependant
|
||||
|
||||
A creation operator that helps at creating observables that have circular
|
||||
dependencies
|
||||
|
||||
```ts
|
||||
const [_resetableCounter$, connectResetableCounter] = selfDependant<number>()
|
||||
|
||||
const clicks$ = new Subject()
|
||||
const inc$ = clicks$.pipe(
|
||||
withLatestFrom(_resetableCounter$),
|
||||
map((_, x) => x + 1),
|
||||
share(),
|
||||
)
|
||||
|
||||
const delayedZero$ = of(0).pipe(delay(10_000))
|
||||
const reset$ = inc$.pipe(switchMapTo(delayedZero$))
|
||||
|
||||
const resetableCounter$ = merge(inc$, reset$, of(0)).pipe(
|
||||
connectResetableCounter(),
|
||||
)
|
||||
```
|
||||
|
||||
### suspend
|
||||
|
||||
```ts
|
||||
const story$ = selectedStoryId$.pipe(
|
||||
switchMap(id => suspend(getStory$(id))
|
||||
)
|
||||
```
|
||||
|
||||
A RxJS creation operator that prepends a `SUSPENSE` on the source observable.
|
||||
|
||||
### suspended
|
||||
|
||||
```ts
|
||||
const story$ = selectedStoryId$.pipe(
|
||||
switchMap((id) => getStory$(id).pipe(suspended())),
|
||||
)
|
||||
```
|
||||
|
||||
The pipeable version of `suspend`
|
||||
|
||||
### switchMapSuspended
|
||||
|
||||
```ts
|
||||
const story$ = selectedStoryId$.pipe(switchMapSuspended(getStory$))
|
||||
```
|
||||
|
||||
Like `switchMap` but applying a `startWith(SUSPENSE)` to the inner observable.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user