Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/johnlindquist/react-streams


https://github.com/johnlindquist/react-streams

react rxjs

Last synced: 19 days ago
JSON representation

Awesome Lists containing this project

README

        

# react-streams

react-streams logo

## 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}
    {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


)}

)
```