Javascript 在 componentWillUnmount 方法中取消所有订阅和异步,如何?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 
原文地址: http://stackoverflow.com/questions/52061476/
Warning: these are provided under cc-by-sa 4.0 license.  You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Cancel All Subscriptions and Asyncs in the componentWillUnmount Method, how?
提问by Dres
I'm getting an error message due to an async method issue. In my terminal I'm seeing:
由于异步方法问题,我收到一条错误消息。在我的终端中,我看到:
Warning: Can't call setState (or forceUpdate) 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 the componentWillUnmount method.
- node_modules/fbjs/lib/warning.js:33:20 in printWarning
- node_modules/fbjs/lib/warning.js:57:25 in warning
- node_modules/react-native/Libraries/Renderer/ReactNativeRenderer-dev.js:12196:6 in warnAboutUpdateOnUnmounted
- node_modules/react-native/Libraries/Renderer/ReactNativeRenderer-dev.js:13273:41 in scheduleWorkImpl
- node_modules/react-native/Libraries/Renderer/ReactNativeRenderer-dev.js:6224:19 in enqueueSetState
- node_modules/react/cjs/react.development.js:242:31 in setState
* router/_components/item.js:51:16 in getImage$
- node_modules/regenerator-runtime/runtime.js:62:44 in tryCatch
- node_modules/regenerator-runtime/runtime.js:296:30 in invoke
- ... 13 more stack frames from framework internals
I noticed it's specifically pointing out the getImage$
我注意到它特别指出 getImage$
Here's the code I'm using for that section:
这是我用于该部分的代码:
export default class extends Component {
    constructor(props) {
        super(props);
        const { item } = props
        const bindThese = { item }
        this.boundActionCreators = bindActionCreators(bindThese)
        this.state = {
            image: require('../../static/logo.png'),
            ready: false,
            showOptions: this.props.showOptions
        }
        this.getImage = this.getImage.bind(this)
        this.renderNotAdmin = this.renderNotAdmin.bind(this)
        this.renderAdmin = this.renderAdmin.bind(this)
        this.handleOutOfStock = this.handleOutOfStock.bind(this)
    }
    async getImage(img) {
        let imgUri = await Amplify.Storage.get(img)
        let uri = await CacheManager.get(imgUri).getPath()
        this.setState({
            image: { uri },
            ready: true
        })
    }
    componentDidMount() {
        this.getImage(this.props.item.image)
    }
I'm trying to figure out how to use a componentWillUnmountwith this async method. How do I go about it?
我正在尝试弄清楚如何将 acomponentWillUnmount与这种异步方法一起使用。我该怎么做?
Thanks!
谢谢!
回答by Sakhi Mansoor
You can use isMountedReact pattern to avoid memory leaks here.
你可以isMounted在这里使用React 模式来避免内存泄漏。
In your constructor:
在您的构造函数中:
constructor(props) {
    super(props);
    this._isMounted = false;
// rest of your code
}
componentDidMount() {
    this._isMounted = true;
    this._isMounted && this.getImage(this.props.item.image);
}
}
in your componentWillUnmount
在你的 componentWillUnmount
componentWillUnmount() {
   this._isMounted = false;
}
While in you getImage()
虽然在你 getImage()
async getImage(img) {
    let imgUri = await Amplify.Storage.get(img)
    let uri = await CacheManager.get(imgUri).getPath()
    this._isMounted && this.setState({
        image: { uri },
        ready: true
    })
}
A recommend approach to use Axioswhich is based cancellable promise pattern. So you can cancel any network call while unmounting the component with it's cancelToken subscription. 
Here is resource for Axios Cancellation
使用基于可取消承诺模式的Axios 的推荐方法。因此,您可以在卸载组件时取消任何网络调用cancelToken subscription。这是Axios 取消的资源
回答by Keir Lewis
From the React blog
来自React 博客
Just set a _isMounted property to true in componentDidMount and set it to false in componentWillUnmount, and use this variable to check your component's status.
只需在 componentDidMount 中将 _isMounted 属性设置为 true 并在 componentWillUnmount 中将其设置为 false,然后使用此变量检查组件的状态。
It goes on to say that ideally, this would instead be fixed by using cancellable callbacks, although the first solution seems suitable here.
它继续说,理想情况下,这将通过使用可取消的回调来修复,尽管第一个解决方案在这里似乎合适。
What you definitely shouldn't do is use the isMounted() function, which may be deprecated.
您绝对不应该使用 isMounted() 函数,该函数可能已被弃用。
回答by KARTHIKEYAN.A
You need to set this.mounted = false in componentWillUnmount() method and this.mounted = true in componentDidMount() method.
您需要在 componentWillUnmount() 方法中设置 this.mounted = false ,在 componentDidMount() 方法中设置 this.mounted = true 。
The setState update is conditional based need to declare in componentDidMount() method.
setState 更新是基于条件的,需要在 componentDidMount() 方法中声明。
componentDidMount() {
        this.mounted = true;
        var myVar =  setInterval(() => {
                let nextPercent = this.state.percentage+10;
                if (nextPercent >= 100) {
                    clearInterval(myVar);
                }
                if(this.mounted) {
                    this.setState({ percentage: nextPercent });
            }
        }, 100);
}
componentWillUnmount(){
      this.mounted = false;
}

