본문 바로가기
✘✘✘ Javascript/RxJs (Reactive Javascript)

[RxJs][React] how to declare Observable properly inside a component?

by PrettyLog 2023. 5. 6.

1. just declare

import React, { useState, useEffect, useMemo } from 'react';
import { interval } from 'rxjs';

export default function App() {
  const [state, setState] = useState();

  const observable$ = useMemo(() => interval(1000), []);

  return (
    <div>
      <h1>Hello RxJS!</h1>
      <p>Observable value: {state}</p>
    </div>
  );
}

2. subscribe

    useEffect(() => {
    const subscription = observable$.subscribe(setState);
  }, []);

3. unsubscribe before componentDidUnmount

    useEffect(() => {
    const subscription = observable$.subscribe(setState);
    return () => subscription.unsubscribe();
  }, [])

4. use useMemo to avoid performance issue

In the code snippet you provided, the observable$ is created every time the App component renders. However, it's not a good practice to create a new observable on every render because it could lead to performance issues and unnecessary re-rendering of the component.

const observable$ = useMemo(() => interval(1000), []);

In this updated code, the useMemo hook is used to memoize the observable$. The observable$ will only be re-computed if any of the dependencies in the dependency array change, which is empty in this case. This ensures that the observable$ is created only once and not on every render.

5. use react-observable

import React from 'react';
import { interval } from 'rxjs';
import { useObservable, useSubscription } from 'react-observable';

export default function App() {
  const [state, setState] = useState();
  const observable$ = useObservable(() => interval(1000));

    useSubscription(observable$, (interval: number) => {
        setState(interval);
    });

  return (
    <div>
      <h1>Hello RxJS!</h1>
      <p>Observable value: {state}</p>
    </div>
  );
}

you don't need to worry about memoizing the observable$ and managing the subscription or unsubscription. The useObservable hook takes care of all of that for you, which simplifies the code and ensures better performance.

tip: with pipe operator?

const observable$ = useObservable(() => interval(1000))
    .pipe(filter(v => v % 2 === 1));

In this case, every time a component renders, observable$.pipe part created.

You are creating a new observable derived from the one returned by the useObservable hook. However, keep in mind that the new observable created by the .pipe operator will not be automatically memoized.

  1. use useMemo to memorize new observable
const observable$ = useObservable(() => interval(1000));
const filtered$ = useMemo(
    () => observable$.pipe(filter(v => v % 2 === 1)), 
    []
);
  1. use pipe inside useObservable
const observable$ = useObservable(() => {
    return interval(1000).pipe(filter(v => v % 2 === 1));
});

2 is better I think

reference

댓글