简体   繁体   English

如何清除在组件生命周期中创建的setTimeout?

[英]How can I clear a setTimeout which is created on a component life cycle?

The thing is that I am getting this warning: 问题是我收到以下警告:

Warning: Can't call setState (or forceUpdate) on an unmounted component. 警告:无法在已卸载的组件上调用setState(或forceUpdate)。 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. 要解决此问题,请在componentWillUnmount方法中取消所有订阅和异步任务。

And it is because of this: 正因为如此:

  componentDidUpdate(props, state) {
    const {
      pushNotificationData,
      unassignedPickUpPassengers,
      unassignedDropOffPassengers,
    } = this.props;

    if (props.pushNotificationData !== pushNotificationData) {
      this.applyOpacityForSomeSeconds(0.5, 0);
    }

    if (
      props.unassignedPickUpPassengers !== unassignedPickUpPassengers ||
      props.unassignedDropOffPassengers !== unassignedDropOffPassengers
    ) {
      this.applyOpacityForSomeSeconds(1, 1000);
    }
  }

  applyOpacityForSomeSeconds = (setOpacity, timeout) =>
    setTimeout(() => {
      this.setState({ lastIndexOpacity: setOpacity });
    }, timeout);

How should I clear the timeout on a componentWillUnmount? 如何清除componentWillUnmount的超时? Is that the proper way of doing this or is there any other way? 是这样做的正确方法还是其他方法?

You need to keep a reference of it, like this: 您需要保留一个引用,例如:

applyOpacityForSomeSeconds = (setOpacity, timeout) =>
  clearTimeout(this.timeout) // notice that you don't have to check if this.timeout is null or undefined just let clearTimeout handle it

  this.timeout = setTimeout(() => {
    this.setState({ lastIndexOpacity: setOpacity });
  }, timeout);

Notice, that reference is set at this.timeout = setTimeout(... . You may initialise the reference in the constructor or somewhere else with a null - I always hesitate on this. :) 注意,该引用是在this.timeout = setTimeout(... 。您可以在构造函数中或其他地方使用null初始化该引用-我总是对此很犹豫。

You can move or copy clearTimeout(this.timeout) into componentWillUnmount if you want. 您可以根据需要将clearTimeout(this.timeout)移动或复制到componentWillUnmount

A simple solution: 一个简单的解决方案:

componentWillUnmount() {
  this.isUnmounted = true;
}

Then you can add to your timeout callback: 然后,您可以添加到超时回调中:

setTimeout(() => {
  if (!this.isUnmounted) {
    this.setState({ lastIndexOpacity: setOpacity });
  }
}, timeout);

This will prevent the setState from running if the component is unmounted. 如果卸载了组件,这将阻止setState运行。

setTimeout returns a handle you can use with cancelTimeout . setTimeout返回可以与cancelTimeout使用的cancelTimeout You could drop that handle into your state as well: 您也可以将该句柄置于状态中:

applyOpacityForSomeSeconds = (setOpacity, timeout) => {
    this.setState({
        opacityTimeout: setTimeout(() => {
            this.setState({
                lastIndexOpacity: setOpacity,
                opacityTimeout: null
            });
        }, timeout);
    });
}

componentWillUnmount() {
    if (this.state.opacityTimeout) {
        clearTimeout(this.state.opacityTimeout);
    }
}

Since you have a timeout of 1 second it might be possible, depending on how quickly your application updates props for this component, that you have multiple timeouts running at the same time. 由于您有1秒钟的超时,因此可能有可能同时运行多个超时,具体取决于您的应用程序为此组件更新道具的速度。 In that case, an array of handles might be a better solution: 在这种情况下,句柄数组可能是更好的解决方案:

(assuming your initial state initializes opacityTimeouts to an empty array) (假设您的初始状态将opacityTimeouts初始化为一个空数组)

applyOpacityForSomeSeconds = (setOpacity, timeout) => {
    const handle = setTimeout(() => {
        this.setState({
            lastIndexOpacity: setOpacity,
            opacityTimeouts: this.state.opacityTimeouts.filter(
                h => h !== handle
            )
        });
    }, timeout);

    this.setState({
        opacityTimeouts: [
           ...this.state.opacityTimeouts,
           handle
        ]
    });
}

componentWillUnmount() {
    this.state.opacityTimeouts.forEach(handle => clearTimeout(handle));
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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