应该在React组件中避免Prom吗?

时间:2017-07-10 14:11:24

标签: reactjs redux redux-thunk

我最近在React中遇到了这个错误:

  

warning.js:36警告:setState(...):只能更新已安装或   安装组件。这通常意味着你在一个上调用了setState()   未安装的组件。这是一个无操作。请检查代码   BillingDetails组件。

挖掘后我发现这是因为我在这样的未安装组件中setState造成的:

componentWillMount() {
    this.fetchBillings(this.props.userType);
}

componentWillReceiveProps({ userType }) {
    if (this.props.userType !== userType) {
        this.fetchBillings(userType);
    }
}

fetchBillings = userType => {
    switch (userType) {
        case USER_TYPE.BRAND:
            this.props.fetchBrandBillings()
                .then(() => this.setState({ isLoading: false }));
            return;
        default:
    }
};

fetchBillingsredux-axios action creator,它返回一个承诺

export const fetchBrandBillings = () => ({
    type: FETCH_BRAND_BILLINGS,
    payload: {
        request: {
            method: 'GET',
            url: Endpoints.FETCH_BRAND_BILLINGS,
        },
    },
});

问题在于,当用户在网站上快速移动时,可以在promise解析时卸载组件。

我在项目周围发现了许多地方,我做了这样的事情:

componentWillMount() {
    const { router, getOrder, params } = this.props;
    getOrder(params.orderId).then(action => {
        if (action.type.endsWith('FAILURE')) {
            router.push(`/dashboard/campaign/${params.campaignId}`);
        }
    })
}

现在我开始认为在组件中使用Promise可能是反模式的,因为组件可以随时卸载......

1 个答案:

答案 0 :(得分:2)

  

问题在于,当用户在网站上快速移动时,可以在promise解析时卸载组件。

由于本地承诺不可中断,因此这是完全自然的,应该始终是可以预期的。您可以通过各种方式克服这个问题,但最终需要跟踪组件是否仍以某种方式安装,并且如果未能解决/拒绝,则不要做任何事情。

另外,关于componentWillMount的docs

  

避免在此方法中引入任何副作用或订阅。

考虑到这一点,我建议使用componentDidMount来启动您的提取。总的来说:

componentDidMount() {
    this._isMounted = true;
    this.fetchBillings(this.props.userType);
}

componentWillReceiveProps({ userType }) {
    if (this.props.userType !== userType) {
        this.fetchBillings(userType);
    }
}

componentWillUnmount() {
    this._isMounted = false;
}

fetchBillings = userType => {
    switch (userType) {
        case USER_TYPE.BRAND:
            this.props.fetchBrandBillings().then(() => {
                if (this._isMounted) {
                    this.setState({ isLoading: false });
                }
            });
            return;
        default:
    }
};

此外,尽管这与您的问题没有直接关系,但您需要考虑并行运行多个并行获取调用,从而导致数据竞争。也就是说,以下只是等待随时发生:

start fetch0
start fetch1
finish fetch1 -> update
...
finish fetch0 -> update

为避免这种情况,您可以使用时间戳跟踪您的请求。