Home > other >  React unsubscribe from RxJS subscription in useEffect
React unsubscribe from RxJS subscription in useEffect

Time:02-17

A quick question regarding RxJS in useEffect hooks

I've noticed the React community uses this unsubscribe pattern with RxJS:

useEffect(()=>{
  const sub = interval(10).subscribe()
  return ()=>sub.unsubscribe()
})

I'm curious if this is due to convention/code clarity, or if I'm overlooking something. I would imagine the following would be simpler:

useEffect(()=> interval(10).subscribe().unsubscribe)

However, I could be overlooking something.

CodePudding user response:

This here:

useEffect(()=>{
  const sub = interval(10).subscribe();
  return () => sub.unsubscribe();
});

could be re-written as:

useEffect(()=>{
  const sub = interval(10).subscribe();

  function unsub(){
    sub.unsubscribe();
  }

  return unsub;
});

The key thing to notice is that you're returning a function back to React. unsub isn't called right away, it's called later when the component unmounts.

In fact, you can return aribrary code to be run later:

useEffect(() => {
  /****** 
   * Code that gets called when 
   * effect is run
   ******/ 
  return () => { // <- start of cleanup function 
    /****** 
     * Code that gets called to 
     * clean up the effect later
     ******/
  } // <- end of cleanup function
});

The problem

What you wrote works... for now.

useEffect(() => interval(10).subscribe().unsubscribe)

The issue is that unsubscribe is no actually a function. It's a method on an subscription object. If the implementation of unsubscribe ever changes to use the this keyword, then JavaScript will throw an exception.

To make sure that unsubscribe gets called as a method you could do this:

useEffect(() => {
  const sub = interval(10).subscribe();
  return sub.unsubscribe.bind(sub);
});

You have one less level of indirection this way, though it looks roughly the same.

CodePudding user response:

The useEffect hooks gets called when the component mounts i.e. is loaded by another component either directly in <App> or via any of it's children. So that's when the first part .subscribe() runs. Now you're subscribed as long as the component is mounted.

When the component unmounts, meaning that it's no longer used, the return value gets called. So the unsubscribe() function, which closes the subscription is called.

Your code would try to immediately call the unsubscribe method on the subscription, we only want do that when the component is no longer used.

useEffect docs

  • Related