Skip to content

Instantly share code, notes, and snippets.

@Peeja
Created September 17, 2021 01:47
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 Peeja/6caf790eb3d68e4025cffc6b3162b913 to your computer and use it in GitHub Desktop.
Save Peeja/6caf790eb3d68e4025cffc6b3162b913 to your computer and use it in GitHub Desktop.
Read the latest value of an Observable in a React hook (WIP, stashed from another project when it became unnecessary.)
/**
* @jest-environment jsdom
*/
import { useObservable } from "./useObservable";
import { renderHook, act } from "@testing-library/react-hooks";
import { Subject } from "rxjs";
describe("useObservable()", () => {
it("returns each value emitted by the Observable", () => {
const subject = new Subject<number>();
const { result } = renderHook(() => useObservable(subject));
expect(result.current).toBeUndefined();
act(() => {
subject.next(1);
});
expect(result.current).toBe(1);
act(() => {
subject.next(2);
});
expect(result.current).toBe(2);
});
it("throws errors emitted by the Observable", () => {
const subject = new Subject<number>();
const { result } = renderHook(() => useObservable(subject));
expect(result.current).toBeUndefined();
// BOOKMARK: Why can't I catch this thing?
act(() => {
try {
subject.error(new Error("Something went wrong!"));
1; //?
} catch (e) {
console.log(e);
}
});
expect(result.current).toBe(1);
act(() => {
subject.next(2);
});
expect(result.current).toBe(2);
});
});
import { useEffect, useState } from "react";
import { Observable } from "rxjs";
/**
* Subscribes to an {@link Observable}. First returns `undefined`, then returns
* each value emitted by the Observable.
*
* Note: Currently, Observable errors and completions are ignored.
* @param observable The Observable to watch
* @returns undefined, then each value emitted by the Observable.
*/
export const useObservable = <T>(observable: Observable<T>): T | undefined => {
const [value, setValue] = useState<T>();
// const [error, setError] = useState<unknown>();
// if (error) throw error;
useEffect(() => {
const subscription = observable.subscribe(setValue);
return () => subscription.unsubscribe();
}, [observable, setValue]);
return value;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment