Repository: streamich/react-use
Pull request #331 (2019-05-30 18:45:26)

Use observable


Patch:
diff --git a/babel.config.js b/babel.config.js
index 4bea0c59..b8339150 100644
--- a/babel.config.js
+++ b/babel.config.js
@@ -1,3 +1,4 @@
 module.exports = {
     presets: ['@babel/preset-env', '@babel/preset-react', "@babel/preset-typescript"],
+    plugins: ['@babel/plugin-syntax-dynamic-import']
 };
\ No newline at end of file
diff --git a/package.json b/package.json
index 0a4294b8..c476782b 100644
--- a/package.json
+++ b/package.json
@@ -44,6 +44,7 @@
   },
   "homepage": "https://github.com/streamich/react-use#readme",
   "dependencies": {
+    "@babel/plugin-syntax-dynamic-import": "^7.2.0",
     "copy-to-clipboard": "^3.1.0",
     "nano-css": "^5.1.0",
     "react-fast-compare": "^2.0.4",
diff --git a/src/useObservable.ts b/src/useObservable.ts
index 14a48286..49832492 100644
--- a/src/useObservable.ts
+++ b/src/useObservable.ts
@@ -1,6 +1,16 @@
 import { useEffect, useState } from 'react';
 
-const useObservable = <T>(observable$, initialValue?: T): T | undefined => {
+export interface Observable<T> {
+  subscribe: (
+    listener: (value: T) => void
+  ) => {
+    unsubscribe: () => void;
+  };
+}
+
+function useObservable<T>(observable$: Observable<T>): T | undefined;
+function useObservable<T>(observable$: Observable<T>, initialValue: T): T;
+function useObservable<T>(observable$: Observable<T>, initialValue?: T): T | undefined {
   const [value, update] = useState<T | undefined>(initialValue);
 
   useEffect(() => {
@@ -9,6 +19,6 @@ const useObservable = <T>(observable$, initialValue?: T): T | undefined => {
   }, [observable$]);
 
   return value;
-};
+}
 
 export default useObservable;
diff --git a/src/useSetState.ts b/src/useSetState.ts
index 056eaca6..d0900439 100644
--- a/src/useSetState.ts
+++ b/src/useSetState.ts
@@ -1,6 +1,8 @@
 import { useState } from 'react';
 
-const useSetState = <T extends object>(initialState: T = {} as T): [T, (patch: Partial<T> | ((prevState: T) => Partial<T>)) => void] => {
+const useSetState = <T extends object>(
+  initialState: T = {} as T
+): [T, (patch: Partial<T> | ((prevState: T) => Partial<T>)) => void] => {
   const [state, set] = useState<T>(initialState);
   const setState = patch => {
     set(prevState => Object.assign({}, prevState, patch instanceof Function ? patch(prevState) : patch));


Test patch:
diff --git a/src/__tests__/useObservable.test.tsx b/src/__tests__/useObservable.test.tsx
new file mode 100644
index 00000000..6bba8c87
--- /dev/null
+++ b/src/__tests__/useObservable.test.tsx
@@ -0,0 +1,35 @@
+import { act, renderHook } from 'react-hooks-testing-library';
+import { Subject } from 'rxjs';
+import { useObservable } from '..';
+
+test('default initial value is undefined', () => {
+  const subject$ = new Subject();
+  const { result } = renderHook(() => useObservable(subject$));
+
+  expect(result.current).toBe(undefined);
+});
+
+test('can specify initial value', () => {
+  const subject$ = new Subject();
+  const { result } = renderHook(() => useObservable(subject$, 123));
+
+  expect(result.current).toBe(123);
+});
+
+test('returns the latest value of observables', () => {
+  const subject$ = new Subject();
+  const { result } = renderHook(() => useObservable(subject$, 123));
+
+  act(() => {
+    subject$.next(125);
+  });
+  expect(result.current).toBe(125);
+
+  act(() => {
+    subject$.next(300);
+    subject$.next(400);
+  });
+  expect(result.current).toBe(400);
+});
+
+xtest('subscribes to observable only once', () => {});