Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/johnlindquist/react-streams
https://github.com/johnlindquist/react-streams
react rxjs
Last synced: 19 days ago
JSON representation
- Host: GitHub
- URL: https://github.com/johnlindquist/react-streams
- Owner: johnlindquist
- Created: 2018-04-05T19:05:00.000Z (over 6 years ago)
- Default Branch: master
- Last Pushed: 2018-08-15T19:06:39.000Z (over 6 years ago)
- Last Synced: 2024-11-17T05:04:04.390Z (27 days ago)
- Topics: react, rxjs
- Language: JavaScript
- Homepage: http://react-streams.com
- Size: 1.18 MB
- Stars: 232
- Watchers: 13
- Forks: 17
- Open Issues: 5
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
- awesome-list - react-streams
README
# react-streams
## Installation
Install both `react-streams` and `rxjs`
```bash
npm i react-streams rxjs
```## Build Status
[![CircleCI](https://circleci.com/gh/johnlindquist/react-streams.svg?style=svg)](https://circleci.com/gh/johnlindquist/react-streams)
[Cypress Dashboard](https://dashboard.cypress.io/#/projects/ar6axg/)
## About
`react-streams` enables you to stream from a source or props. The stream will pass through a `pipe` and new values will often be pushed through by `plans`.
### Stream from sources
**_``_** - A component that subscribes to a `source` and streams values to children. The stream will pass through a `pipe`.
> ```js
>
> {values =>{values.message}}
>
> ```**_`stream(source)`_** - Creates a named component that subscribes to a `source` and streams values to children. The stream will pass through a `pipe`.
> ```js
> const MyStreamingComponent = stream(source$)
>
>
> {(values)=>{values.message}}
>
> ```### Stream from props
**_``_** - A component that streams props changes to children. Changes to props will pass through the `pipe` and can be updated by `plans`.
> ```js
>
> {values =>{values.message}}
>
> ```**_`streamProps()`_** - Create a named component that streams props changes to children. Changes to props will pass through the `pipe` and can be updated by `plans`.
> ```js
> const MyStreamingPropsComponent = streamProps()
>
>
> {(values)=>{values.message}}
>
> ```### Stream through `pipe`
**_`pipe`_** is any operator (or `piped` combination of operators) that you want to act on your stream. Pipes can be simple mappings or complex ajax requests with timing as long as they return a function that returns an object which matches the `children`'s arguments.
> ```js
> message={message}
> pipe={map(({ message }) => message + "!")}
> >
> {values =>{values.message}}
>
> ```### Make a `plan` to update
**_`plan`_** is a function that can be observed.
> ```js
> const update = plan()
>
> from(update).subscribe(value => console.log(value))
>
> update("Hello") //logs "Hello"
> update("Friends") //logs "Friends"
> ```## Examples
Enough chit-chat, time for examples!
Play with Examples at [codesandbox.io](https://codesandbox.io/s/github/johnlindquist/react-streams/tree/master/examples?module=/stream/index.js)
### ``
[Demo here](https://codesandbox.io/s/github/johnlindquist/react-streams/tree/master/examples?module=generic/index.js)
```js
import React from "react"
import { Stream } from "react-streams"
import { of, pipe } from "rxjs"
import { delay, startWith } from "rxjs/operators"const startWithAndDelay = (message, time) =>
pipe(
delay(time),
startWith({ message })
)const message$ = of({ message: "Hello" })
export default () => (
Stream as a Component
{({ message }) =>{message}}
{({ message }) =>{message}}
)
```### `stream`
[Demo here](https://codesandbox.io/s/github/johnlindquist/react-streams/tree/master/examples?module=/stream/index.js)
```js
import React from "react"
import { stream } from "react-streams"
import { interval } from "rxjs"
import { map } from "rxjs/operators"const count$ = interval(250).pipe(
map(count => ({ count }))
)const Counter = stream(count$)
export default () => (
Subscribe to a Stream
{({ count }) =>{count}}
)
```### `pipe`
[Demo here](https://codesandbox.io/s/github/johnlindquist/react-streams/tree/master/examples?module=/pipe/index.js)
```js
import React from "react"
import { stream } from "react-streams"
import { of } from "rxjs"
import { map } from "rxjs/operators"const stream$ = of({ greeting: "Hello", name: "world" })
const mapToMessage = map(({ greeting, name }) => ({
message: `${greeting}, ${name}!`
}))const Greeting = stream(stream$, mapToMessage)
export default () => (
Pipe Stream Values
{({ message }) =>{message}}
)
```### `streamProps`
[Demo here](https://codesandbox.io/s/github/johnlindquist/react-streams/tree/master/examples?module=/streamProps/index.js)
```js
import React from "react"
import { streamProps } from "react-streams"
import { map } from "rxjs/operators"const mapGreeting = map(({ greeting, name }) => ({
message: `${greeting}, ${name}!`
}))const HelloWorld = streamProps(mapGreeting)
export default () => (
Stream Props to Children
{({ message }) =>{message}}
{({ message }) =>{message}}
)
```### Ajax
[Demo here](https://codesandbox.io/s/github/johnlindquist/react-streams/tree/master/examples?module=/ajax/index.js)
```js
import React from "react"
import { streamProps } from "react-streams"
import { pipe } from "rxjs"
import { ajax } from "rxjs/ajax"
import {
pluck,
switchMap,
startWith
} from "rxjs/operators"const getTodo = pipe(
switchMap(({ url, id }) => ajax(`${url}/${id}`)),
pluck("response")
)const Todo = streamProps(getTodo)
const url = process.env.DEV
? "/api/todos"
: "https://dandelion-bonsai.glitch.me/todos"export default () => (
Ajax Demo
{({ text, id }) => (
{id}. {text}
)}
{({ text, id }) => (
{id}. {text}
)}
)
```### Nested Streams
[Demo here](https://codesandbox.io/s/github/johnlindquist/react-streams/tree/master/examples?module=/nested/index.js)
```js
import React from "react"
import { Stream, StreamProps } from "react-streams"
import { map, filter } from "rxjs/operators"
import { interval } from "rxjs"const count$ = interval(1000).pipe(
map(count => ({ count }))
)const odds = filter(({ count }) => count % 2)
const evens = filter(({ count }) => !(count % 2))export default () => (
{({ count }) => (
Stream with Nested StreamProps Components
{({ count }) =>No filter: {count}}
{({ count }) =>Odds: {count}}
{({ count }) =>Evens: {count}}
)}
)
```### Create a `plan`
[Demo here](https://codesandbox.io/s/github/johnlindquist/react-streams/tree/master/examples?module=/plans/index.js)
```js
import React from "react"
import { StreamProps, plan } from "react-streams"
import { map, pluck } from "rxjs/operators"const onChange = plan(
pluck("target", "value"),
map(message => ({ message }))
)export default () => (
Update a Stream with Plans
{({ message, onChange }) => (
{message}
)}
)
```### `scanPlans`
[Demo here](https://codesandbox.io/s/github/johnlindquist/react-streams/tree/master/examples?module=/plans/index.js)
```js
import React from "react"
import {
scanPlans,
plan,
streamProps
} from "react-streams"
import { pipe } from "rxjs"
import { ajax } from "rxjs/ajax"
import {
debounceTime,
distinctUntilChanged,
map,
pluck
} from "rxjs/operators"const handleInput = pipe(
pluck("target", "value"),
debounceTime(250),
distinctUntilChanged(),
/**
* map to a fn which returns an object, fn, or Observable (which returns an
* object, fn, or Observable)
*/
map(term => props => {
if (term.length < 2) return { people: [], term: "" }
return ajax(
`${props.url}?username_like=${term}`
).pipe(
pluck("response"),
map(people => ({
term,
people: people.slice(0, 10)
}))
)
})
)const Typeahead = streamProps(
scanPlans({ onChange: plan(handleInput) })
)const url = process.env.DEV
? "/api/people"
: "https://dandelion-bonsai.glitch.me/people"export default () => (
{({ term, people, onChange }) => (
Search a username: {term}
{people.map(person => (
{person.username}
))}
)}
)
```### Counter Demo
[Demo here](https://codesandbox.io/s/github/johnlindquist/react-streams/tree/master/examples?module=/counter/index.js)
```js
import React from "react"
import {
scanPlans,
plan,
streamProps
} from "react-streams"
import { map } from "rxjs/operators"const onInc = plan(
map(() => state => ({ count: state.count + 2 }))
)
const onDec = plan(
map(() => state => ({ count: state.count - 2 }))
)
const onReset = plan(map(() => state => ({ count: 4 })))const Counter = streamProps(
scanPlans({ onInc, onDec, onReset })
)export default () => (
{({ count, onInc, onDec, onReset }) => (
-
{count}
+
Reset
)}
)
```