LeetCode-OpenSource/rxjs-hooks

Error and loading state guide

Brooooooklyn opened this issue · 2 comments

Expose API like:

const value = useObservable((props$: Observable<[number, string]>) => props$.pipe(
  switchMap(([n, s]) => httpRequest.query(`https://mockbackend?n=${n}&s=${s}`)),
))

Sample:

check the demo here: https://codesandbox.io/s/q94yj41m1j

const mockRequest = (function() {
  let counter = 0;

  return function() {
    counter++;
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        if (counter > 2 && counter < 10) {
          reject(new Error("mockError"));
        }
        resolve("We're cool");
      }, 800);
    });
  };
})();

function App() {
  const [isLoading, setLoading] = useState(false);
  const [err, setError] = useState(null);
  const [clickCallback, status] = useEventCallback(
    (event$, state$) =>
      event$.pipe(
        tap(() => {
          setLoading(true);
          setError(null);
        }),
        switchMap(event => {
          return from(mockRequest()).pipe(
            catchError(error => {
              setError(error);
              return of("got error");
            })
          );
        }),
        tap(() => setLoading(false))
      ),
    "nothing"
  );

  return (
    <div className="App">
      <p>
        {isLoading ? "is loading!...." : `${status}`}
        {err && ` - ${err.toString()}`}
      </p>
      <button onClick={clickCallback}>send request</button>
    </div>
  );
}
Fyzu commented

@zry656565 More clear example, without dirty tap

const mockRequest = (function() {
  let counter = 0;

  return function() {
    counter++;
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        if (counter > 2 && counter < 10) {
          reject(new Error("mockError"));
        }
        resolve("We're cool");
      }, 800);
    });
  };
})();

function App() {
  const [clickCallback, [status, result]] = useEventCallback(
    (event$, state$) =>
      event$.pipe(
        switchMap(event => {
          return from(mockRequest()).pipe(
            map(result => ["success", result]),
            catchError(error => {
              return of(['error', error]);
            }),
            startWith(["loading", null])
          );
        })
      ),
    ["nothing", null]
  );

  const isSuccess = status === "success";
  const isError = status === "error";

  return (
    <div className="App">
      <p>
        {isSuccess ? result : status}
        {isError && ` - ${result.toString()}`}
      </p>
      <button onClick={clickCallback}>send request</button>
    </div>
  );
}