https://github.com/kosich/rxjs-proxify
Turns a Stream of Objects into an Object of Streams
https://github.com/kosich/rxjs-proxify
observable proxy reactive-programming rxjs rxjs-observables
Last synced: over 1 year ago
JSON representation
Turns a Stream of Objects into an Object of Streams
- Host: GitHub
- URL: https://github.com/kosich/rxjs-proxify
- Owner: kosich
- License: mit
- Created: 2020-09-17T19:08:35.000Z (almost 6 years ago)
- Default Branch: master
- Last Pushed: 2021-06-13T08:48:19.000Z (about 5 years ago)
- Last Synced: 2025-03-24T20:38:44.311Z (over 1 year ago)
- Topics: observable, proxy, reactive-programming, rxjs, rxjs-observables
- Language: TypeScript
- Homepage:
- Size: 1.44 MB
- Stars: 36
- Watchers: 3
- Forks: 3
- Open Issues: 7
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
Access values inside RxJS Observables as if they were directly available on the stream!
```ts
stream.pipe(pluck('msg')).subscribe(β¦);
// turn β into β
stream.msg.subscribe(β¦);
```
With good TypeScript support! π² Roughly speaking:
```ts
proxify( Observable<{ msg: string }> ) β Observable<{ msg: string }> & { msg: Observable }
```
**But recursively.** So `stream.msg` is a Proxy itself, allowing you to `stream.msg.length.subscribe(β¦)`!
Proxify lets you **access Observable API** as well as **pluck props** and **call methods** at any depth of an Observable, Subject, or BehaviorSubject! See the [API](#-api) and [Examples](#-examples) sections to learn more.
## π¦ Install
```
npm i rxjs-proxify
```
or [try it online](https://stackblitz.com/edit/rxjs-proxify-repl?file=index.ts)!
## π API
There are two methods available to you: [`proxify`](#proxify) and [`statify`](#statify)
## Proxify
`proxify(stream)` will wrap your Observable, Subject or BehaviorSubject in a Proxy:
**Observable Proxy**
subscribe at any depth
```ts
const observable = proxify( of({ p: 'π' }) );
observable.subscribe(console.log); // > { p: π }
observable.p.subscribe(console.log); // > π
```
**Subject Proxy**
subscribe at any depth, push at the root
```ts
const subject = proxify(new Subject<{ p: string }>());
subject.subscribe(console.log);
subject.p.subscribe(console.log);
subject.next({ p: 'π₯' }); // > { p: π₯ } // > π₯
```
**BehaviorSubject Proxy**
subscribe at any depth, push at any depth, synchronously read the current state
```ts
const behavior = proxify(new BehaviorSubject({ p: 'π' }));
behavior.p.subscribe(console.log); // > π
behavior.p.next('π'); // > π
console.log(behavior.p.value) // > π
```
### Statify
`statify(value)` will put the value in a BehaviorSubject Proxy and add a `distinctUntilChanged` operator on each property access.
**State Proxy**
subscribe to distinct updates at any depth, push at any depth, synchronously read the current state
```ts
// create a state
const state = statify({ a: 'π°', z: 'π‘' });
// listen to & log root state changes
state.subscribe(console.log); //> { a:π° z:π‘ }
// update particular substate
state.a.next('π'); //> { a:π z:π‘ }
// read current values
console.log(state.z.value + state.a.value); //> π‘π
// update root state, still logging
state.next({ a: 'π', z: 'βοΈ' }) //> { a:π z:βοΈ }
// and thenβ¦
state.z.next('π'); //> { a:π z:π }
state.a.next('ππ'); //> { a:ππ z:π }
state.z.next('πΈ') //> { a:ππ z:πΈ }
state.a.next('π¨'); //> { a:π¨ z:πΈ }
```
See Examples section for more details.
## π Examples
### Basic
```ts
import { proxify } from "rxjs-proxify";
import { of } from "rxjs";
const o = of({ msg: 'Hello' }, { msg: 'World' });
const p = proxify(o);
p.msg.subscribe(console.log);
// equivalent to
// o.pipe(pluck('msg')).subscribe(console.log);
```
### With JS destructuring
Convenient stream props splitting
```ts
import { proxify } from "rxjs-proxify";
import { of } from "rxjs";
const o = of({ msg: 'Hello', status: 'ok' }, { msg: 'World', status: 'ok' });
const { msg, status } = proxify(o);
msg.subscribe(console.log);
status.subscribe(console.log);
// equivalent to
// const msg = o.pipe(pluck('msg'));
// const status = o.pipe(pluck('status'));
// msg.subscribe(console.log);
// status.subscribe(console.log);
```
**β οΈ WARNING:** as shown in "equivalent" comment, this operation creates several Observables from the source Observable. Which means that if your source is _cold_ β then you might get undesired subscriptions. This is a well-known nuance of working with Observables. To avoid this, you can use a multicasting operator on source before applying `proxify`, e.g. with [`shareReplay`](https://rxjs.dev/api/operators/shareReplay):
```ts
const { msg, status } = proxify(o.pipe(shareReplay(1)));
```
### With pipe
Concatenate all messages using `pipe` with `scan` operator:
```ts
import { proxify } from "rxjs-proxify";
import { of } from "rxjs";
import { scan } from "rxjs/operators";
const o = of({ msg: 'Hello' }, { msg: 'World' });
const p = proxify(o);
p.msg.pipe(scan((a,c)=> a + c)).subscribe(console.log);
// equivalent to
// o.pipe(pluck('msg'), scan((a,c)=> a + c)).subscribe(console.log);
```
### Calling methods
Pick a method and call it:
```ts
import { proxify } from "rxjs-proxify";
import { of } from "rxjs";
const o = of({ msg: () => 'Hello' }, { msg: () => 'World' });
const p = proxify(o);
p.msg().subscribe(console.log);
// equivalent to
// o.pipe(map(x => x?.map())).subscribe(console.log);
```
### Accessing array values
Proxify is recursive, so you can keep chaining props or indices
```ts
import { proxify } from "rxjs-proxify";
import { of } from "rxjs";
const o = of({ msg: () => ['Hello'] }, { msg: () => ['World'] });
const p = proxify(o);
p.msg()[0].subscribe(console.log);
// equivalent to
// o.pipe(map(x => x?.map()), pluck(0)).subscribe(console.log);
```
## π€ Want to contribute to this project?
That will be awesome!
Please create an issue before submiting a PR β we'll be able to discuss it first!
Thanks!
## Enjoy π