简体   繁体   中英

How to clean up a Redux "useDispatch" action inside useEffect?

I found a lot of examples for this, but none uses Redux and useDispatch , so here's the situation ...

I have an action file with an async action like this ...

//postsActions.tsx

export const asyncGetPostById = (postId: string) => {
    return async (dispatch: any, getState: () => AppState) => {
        try {
            dispatch(startLoader());
            const { data } = await axios.get(`api/posts/${postId}`);
            dispatch(setPostDataInReducer(data));
        } catch (error) {
            console.log(error)
        }
    };
};

And I'm calling this action inside the Post.tsx component like this ...

const dispatch = useDispatch();

useEffect(() => {
    dispatch(asyncGetPostById(postId));
}, []);

This is of course a simplified version, but it's the same idea. Now how can I clean up a dispatch like that in useEffect to avoid this error ...

Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.

Edit

The idea is how to cancel the request on ComponentWillUnmount (or the cleanup function in useEffect in my case) if it's not done already so that you won't have stale or unresolved requests in the background that will make your app slow.

It's a very common issue that a lot of people fall a victim to, and there's a lot of solutions out there, but not for this particular case (with dispatch and redux).

Some uses AbortController() , and others use axios.CancelToken but I'm not sure how to use either of them in my case.

Try this for your action creator:

export const asyncGetPostById = (postId: string) => async (dispatch: Function, getState: () => AppState) => {
    try {
        dispatch(startLoader());
        const { data } = await axios.get(`api/posts/${postId}`);
        dispatch(setPostDataInReducer(data));
    } catch (error) {
        console.log(error)
    }
};

It's a subtle change, but with this action creator you're not actually returning anything (In TypeScript it would be void )

With a void return, your dispatch calls in the action creator will go straight to your reducer, but in your component nothing will be returned, so you shouldn't have to cleanup anything.

Edit:

Additionally, you should consider adding dispatch to your useEffects dependency array:

const dispatch = useDispatch();

useEffect(() => {
    dispatch(asyncGetPostById(postId));
}, [dispatch]);

You must to create in your reducer a case that clean the current state. And then in useEffect you do like that

React.useEffect(()=> {
 dispatch(your_action)
 return () => dispatch(clean_data_action)
},[])
 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM