在 ReactJS 中卸载组件时取消承诺 [英] Cancel a promise when a component is unmounted in ReactJS

查看:44
本文介绍了在 ReactJS 中卸载组件时取消承诺的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个名为Item"的组件,它在挂载后创建并调用一个 promise.

class Item 扩展了 React.Component{构造函数(道具){超级(道具)this.onClick = this.onClick.bind(this)this.prom = new Promise((resolve, reject) => {setTimeout(() => resolve("承诺完成"+this.props.id),6000)})}componentDidMount(){this.prom.then((成功) => {控制台日志(成功)})}componentWillUnmount(){console.log("卸载")}点击(e){e.preventDefault()this.props.remove(this.props.id)}使成为(){返回 (<h1>项目 {this.props.id} - <a href="#" onClick={this.onClick}>Remove</a></h1>)}}

如您所见,promise 在调用后 6 秒调用了 resolve.

还有一个名为List"的组件负责在屏幕上显示这些项目.List"是Item"组件的父级.

class List 扩展 React.Component{构造函数(道具){超级(道具)this.state = {项目:[1,2,3]}this.handleRemove = this.handleRemove.bind(this)}处理删除(ID){this.setState((prevState, props) => ({项目:prevState.items.filter((cId) => cId != id)}));}使成为(){返回 (<div>{this.state.items.map((item) => (<Item key={item} id={item} remove={this.handleRemove}/>))}

)}}ReactDOM.render(<List/>,root)

在上面的例子中,它在屏幕上显示了三个项目.

如果我移除了这些组件中的任何一个,componentWillUnmount() 会被调用,但在移除的组件中创建的 promise 也会被运行.

例如,即使我删除了第二个项目,我也可以看到第二个项目的承诺正在运行.

已卸载承诺完成 1承诺完成 2承诺完成 3

我必须在卸载组件时取消承诺.

解决方案

此变体 https://hshno.de/BJ46Xb_r7 似乎对我有用.我使用 mounted 实例变量创建了一个 HOC,并将所有异步组件包装在其中.

以下是我的代码大致的样子.

导出函数 makeMountAware(Component) {返回类 MountAwareComponent 扩展了 React.Component {安装 = 假;componentDidMount() {this.mounted = true;}componentWillUnmount() {this.mounted = false;}返回 (<组件安装 = {this.mounted}{...this.props}{...this.state}/>);}}类 AsyncComponent 扩展了 React.Component {componentDidMount() {fetchAsyncData().then(数据=> {this.props.mounted &&this.setState(prevState => ({...prevState,数据}));});}}导出默认 makeMountAware(AsyncComponent);

I've a component named "Item" which creates and calls a promise when it has been mounted.

class Item extends React.Component{
    constructor(props){
        super(props)
        this.onClick = this.onClick.bind(this)

        this.prom = new Promise((resolve, reject) => {
            setTimeout(() => resolve("PROMISE COMPLETED "+this.props.id),6000)
        })
    }

    componentDidMount(){
        this.prom.then((success) => {
            console.log(success)
        })
    }

    componentWillUnmount(){
       console.log("unmounted")
    }

    onClick(e){
        e.preventDefault()
        this.props.remove(this.props.id)
    }

    render(){
        return (
            <h1>Item {this.props.id} - <a href="#" onClick={this.onClick}>Remove</a></h1>
        )
    }
}

As you can see, the promise calls the resolve 6 seconds after it has been called.

There is another component named "List" that is responsible for showing those items on the screen. The "List" is the parent of the "Item" component.

class List extends React.Component{
    constructor(props){
        super(props)
        this.state = {
            items : [1,2,3]
        }

        this.handleRemove = this.handleRemove.bind(this)
    }

    handleRemove(id){
        this.setState((prevState, props) => ({
            items : prevState.items.filter((cId) => cId != id)
        }));
    }

    render(){
        return (
            <div>
            {this.state.items.map((item) => (
                <Item key={item} id={item} remove={this.handleRemove}  />
            ))
            }
            </div>
        )
    }
}

ReactDOM.render(<List />,root)

On the example above, it shows three Item on the screen.

If I remove any of those components, componentWillUnmount() is called but also the promise which has been created in the removed component is run.

For example, I can see the promise of the second item is run even if I remove the second item.

unmounted 
PROMISE COMPLETED 1 
PROMISE COMPLETED 2 
PROMISE COMPLETED 3

I have to cancel the promise when a component is unmounted.

解决方案

A variation of this https://hshno.de/BJ46Xb_r7 seemed to work for me. I made an HOC with the mounted instance variable and wrapped all async components in it.

Below is what my code roughly loks like.

export function makeMountAware(Component) {
    return class MountAwareComponent extends React.Component {
        mounted = false;
        componentDidMount() {
            this.mounted = true;
        }
        componentWillUnmount() {
            this.mounted = false;
        }
        return (
            <Component 
                mounted = {this.mounted}
                {...this.props}
                {...this.state}
            />
        );
    }
}

class AsyncComponent extends React.Component {
    componentDidMount() {
        fetchAsyncData()
            .then(data => {
                this.props.mounted && this.setState(prevState => ({
                    ...prevState,
                    data
                }));
            });
    }
}
export default makeMountAware(AsyncComponent);

这篇关于在 ReactJS 中卸载组件时取消承诺的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆