Skip to content

Instantly share code, notes, and snippets.

@MattSPalmer
Last active August 27, 2019 18:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MattSPalmer/3727f84a3b430ea1786d84563f6e67e7 to your computer and use it in GitHub Desktop.
Save MattSPalmer/3727f84a3b430ea1786d84563f6e67e7 to your computer and use it in GitHub Desktop.
import _ from 'underscore';
import { useState, useEffect } from 'react';
import { isObservable } from 'rxjs';
const useObservable = (observable, initial) => {
const [next, setNext] = useState(initial);
const [isComplete, setIsComplete] = useState(false);
const [error, setError] = useState();
useEffect(
() => {
setIsComplete(false);
setError();
if (!isObservable(observable)) {
setError(
new TypeError(
`useObservable expected Observable, got ${typeof observable}`
)
);
return _.noop;
}
const subscription = observable.subscribe({
next: (value) => setNext(value),
complete: () => setIsComplete(true),
error: (err) => setError(err)
});
return () => {
subscription.unsubscribe();
};
},
[observable]
);
return [next, isComplete, error];
};
export default useObservable;
import { useMemo } from "react";
import * as Rx from "rxjs";
import * as op from "rxjs/operators";
import useObservable from "./use-observable";
const makeReactiveStore = (reducer$, initial) => {
const action$ = new Rx.Subject();
let state;
const state$ = reducer$(action$).pipe(
op.startWith(initial),
op.shareReplay(1)
);
state$.subscribe(x => {
state = x;
});
return {
state$,
getState() {
return state;
},
dispatch(action) {
action$.next(action);
}
};
};
const useStore = (reducer$, initial) => {
const store = useMemo(
() => makeReactiveStore(reducer$, initial),
// eslint-disable-next-line react-hooks/exhaustive-deps
[reducer$]
);
const [state, isComplete, error] = useObservable(state$);
return [state, dispatch, isComplete, error];
};
export default useStore;
export const newSharedStoreHook = (reducer$, initial) => {
const action$ = new Rx.Subject();
const dispatch = action => action$.next(action);
const state$ = reducer$(action$).pipe(
op.startWith(initial),
op.shareReplay(1)
);
return () => {
const [state, isComplete, error] = useObservable(state$);
return [state, dispatch, isComplete, error];
};
};
export const useDispatchController = (dispatch, controller) => {
const obs$ = useMemo(
() =>
controller.pipe(
op.tap(dispatch),
op.concatMapTo(Rx.EMPTY)
),
[dispatch, controller]
);
const [, isComplete, error] = useObservable(obs$);
return [isComplete, error];
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment