-1

In many code examples I see something like this:

const [items, setItems] = useState([]);
useEffect(() => {
    setItems(store.getState().items.length);
    
    
    const unsubscribe = store.subscribe(() => {
        setItems(store.getState().items.length);
    });
    
    return unsubscribe; // <-- huh?
}, []);

My question is; how does returning a reference to the subscription unsubscribe from it?

JCraine
  • 1,159
  • 2
  • 20
  • 38

4 Answers4

1

.subscribe returns a function that unsubscribes the change listener. That is what you return from useEffect callback and is called as cleanup.

It gets called automatically. So questioning that is like questioning how does useEffect run after renders. React takes care of this so you do not have to worry.

Tushar Shahi
  • 16,452
  • 1
  • 18
  • 39
1
const unsubscribe = store.subscribe(() => {
   setItems(store.getState().items.length);
});

This call to store.subscribe immediately creates a subscription with the redux store, and then redux returns a function to you. This returned function is an unsubscribe function which knows how to tear down the subscription. If you're curious, here's the source code where they create that function.

return unsubscribe;

By returning the unsubscribe function, you tell react "hey, when it's time to tear down this effect, please run unsubscribe". React will then call it at the appropriate time: either when the component unmounts, or when the dependencies on the effect change.

Nicholas Tower
  • 72,740
  • 7
  • 86
  • 98
0

the cleanup function runs before every render. So every render it will run before the useEffect. It will also be executed when the component unmounts, and then of course the rest of the useEffect will not run anymore

Jelte Homminga
  • 249
  • 2
  • 10
  • What I'm unclear on is how is it actually unsubscribing? Isn't it RE-subscribing, since it's running the subscription again on unmount? – JCraine Oct 08 '22 at 13:11
  • 1
    `Isn't it RE-subscribing, since it's running the subscription again on unmount?` The only thing it runs on unmount is `unsubscribe`. `unsubscribe` is a function that redux created for you, which knows how to destroy the subscription. https://redux.js.org/api/store/#returns-2 – Nicholas Tower Oct 08 '22 at 13:13
  • Ah gotcha, so this is a redux specific feature? Re-executing a subscription function destroys it? – JCraine Oct 08 '22 at 13:18
  • 1
    It's redux-specific, but there is no re-executing involved. Unsubscribe gets called only once. While the effect is running, you call store.subscribe. This returns a *different* function to you, and you assign it to the variable named `unsubscribe`. When the effect gets torn down, that different function gets called. – Nicholas Tower Oct 08 '22 at 13:21
0

The useEffect cleanup function allows applications to prevent having memory leaks by 'cleaning up' any effects. In a basic example you have this structure

useEffect(() => {
        effect
        return () => {
            cleanup
        }
    }, [input])

Here you will see the useEffect method will run an effect whenever an input in the dependancy array gets updated. So if your useEffect returns a function once it's time to unmount (or update) it'll run that function.

As for how it works think of the logic, when the component mounts we run the code and store the result. When it comes time to unmount or rerender the stored result will run first cleaning up any logic.

Now more specific to your code I don't think it makes sense, you should investigate the store.subscribe method and that will most likely answer your question.

EDIT after seeing the Link to the code you'll see the initial question had a memory leak in it.