GX博客

分享个人 Full-Stack JavaScript 项目开发经验

在React组件unmounted之后setState的报错处理

我们知道,在 React 类组件的 componentWillUnmount 生命周期方法中,必须移除定时器、移除事件监听、取消网络请求、销毁第三库实例以及清理任何在 componentDidMount 环节创建的 DOM 元素等。

在使用 react-redux 后,fetch 请求从 React 中剥离。有些时候,我们想在 fetch 获得响应后再调用组件内的方法,如 this.setState,亦不想请求因组件移除而被取消。若获得响应时,组件已经被移除,则会导致互相引用,React 抛出一个错误,告诉你这样会导致内存溢出。


我们可以使用dispatchEvent,利用事件分发和监听机制避免这一问题。下面对这一过程做简单介绍:

定义 actionCreator,接收回调函数的引用。

export function delete_something(ids, cb) {
    return function (dispatch) {
        // ......
        return fetchThenDispatch('request_url','POST', JSON.stringify({ids}), function(json){
            // ......
            cb && cb();
        });
    }
}

在容器组件中连接回调函数属性,使其分发这个 Action。

import {connect} from "react-redux";
import {delete_something} from "../actionCreator/list";
import {ListUI} from "../components/list/list";

export const ListContainer = connect(
    state => (
        // ...
    ), dispatch => (
        {
            onDeleteSomething(ids, callback) {
                dispatch(delete_something(ids, callback));
            }
        }
    )
)(ListUI);

在 actionCreator 的回调函数中,我们在 window 上分发一个事件,而不是调用组件上下文 this 的方法。需要执行的操作通过组件内的事件监听函数执行,组件移除时,移除这个事件监听。

import React from "react";

class Example extends React.Component {
    // ......
    clickHandle = ()=> {
       // ......
       // 在时间处理函数中执行回调函数属性
       this.props.onDeleteSomething(this.ids, () => {

            // 待 actionCreator 的 fetch 响应后在 window 上分发一个事件;
            const event = new Event(this.eventName);
            // 也可实用传递参数的自定义事件
            // const event = new CustomEvent(this.eventName, {'detail': {your_data: '...'})
            // e.detail
            window.dispatchEvent(event);
        });
    };
    componentDidMount() {
        // ......
        window.addEventListener(this.eventName, this.deleteHandle);
    }
    componentWillUnmount() {
        // 移除删除监听
        window.removeEventListener(this.eventName, this.deleteHandle);
    }
}

版权声明:

本文为博主原创文章,若需转载,须注明出处,添加原文链接。

https://leeguangxing.cn/blog_post_25.html