lukeed/vegemite

Dispatching with useEffect cleanup function

Closed this issue · 2 comments

I am using vegemite with Rxdb

In a React component:

useEffect(() => {
	store.listen(setState);
	store.dispatch('loadData'); // load data and subscribe a function for state update 
	return () => { // cleanup function
		store.dispatch('onUnloadData');  // unsubscribe methods
	};
}, []);

store.on('onUnloadData', (state) => { subs.forEach((sub) => sub.unsubscribe()); });

When calling store.dispatch('onUnloadData');
Occurs an error: "Can't perform a React state update on an unmounted component."

Because all dispatch functions performs state update. So store.dispatch('onUnloadData'); performs new state update.

We need a store.slientDispatch('onUnloadData') like function.

Currently I am using a solution. Using store.destroy() function rather than dispatching onUnloadData like event.

store['destroy'] = () => { subs.forEach((sub) => sub.unsubscribe()); };

May be the that thought:

 // only event dispatching so do not perform state update
store.manuelDispatch(event)

// or optionally state update without klona library
store.manuelDispatch(event, (state)=> {
    const newState = {...state};
    // ... some state update on newState
    return newState;
})

if this is ok i can send a pull request.

Hi there,

It might help to see more code, but your useEffect isn't cleaning itself up and that's your problem. I'll direct you to this example, especially if you haven't seen it before.

You'll notice that I return the store.listen(...) directly. This tells P/React that it needs to call the unsubscriber function that store.listen returned.

In your example, you never unsubscribe, and so that's why you get the error. When you think the store is done listening & calling setState, it's not.

How about trying this instead:

useEffect(() => {
  let unsub = store.listen(setState);
  store.dispatch('loadData');
  return () => {
    store.dispatch('onUnloadData').then(unsub); // <~ unsubscribe
  };
});