有没有办法检查反应组件是否已卸载?

时间:2016-09-29 10:13:55

标签: javascript reactjs

我有一个用例,我需要卸载我的反应组件。但在某些情况下,特定的反应组分是由不同的功能卸载的。 因此,我需要在卸载之前检查组件是否已安装。

10 个答案:

答案 0 :(得分:75)

由于isMounted()正式弃用,您可以在组件中执行此操作:

componentDidMount() { 
  this._ismounted = true;
}

componentWillUnmount() {
   this._ismounted = false;
}

ReactJS文档中详细介绍了维护自己的state变量的模式:https://facebook.github.io/react/blog/2015/12/16/ismounted-antipattern.html

答案 1 :(得分:19)

我认为Shubham的回答是针对那些需要转换代码以停止使用isMounted反模式的人的反应建议。

这不一定是坏事,但值得列出这个问题的真正解决方案。

The article linked by Shubham提供了2条避免这种反模式的建议。您需要的那个取决于卸载组件时调用setState的原因。

  

如果您在组件中使用Flux存储,则必须取消订阅componentWillUnmount

class MyComponent extends React.Component {
  componentDidMount() {
    mydatastore.subscribe(this);
  }
  render() {
    ...
  }
  componentWillUnmount() {
    mydatastore.unsubscribe(this);
  }
}
  

如果您使用ES6承诺,您可能需要包装您的承诺以使其可取消。

const cancelablePromise = makeCancelable(
  new Promise(r => component.setState({...}}))
);

cancelablePromise
  .promise
  .then(() => console.log('resolved'))
  .catch((reason) => console.log('isCanceled', reason.isCanceled));

cancelablePromise.cancel(); // Cancel the promise

在链接文章中详细了解makeCancelable

总之,不要尝试通过设置变量并检查组件是否已挂载来修补此问题,转到问题的根源。如果您能提出任何常见案例,请对其进行评论。

答案 2 :(得分:7)

另一个解决方案是使用Refs。如果您使用的是React 16.3+,请在渲染功能中引用您的顶级项目。

然后只需检查ref.current是否为空。

示例:

class MyClass extends React.Component {
  constructor(props) {
    super(props);
    this.elementRef = React.createRef();
  }

  checkIfMounted() {
     return this.elementRef.current != null;
  }

  render() {
    return (
      <div ref={this.elementRef} />
    );
  }
}

答案 3 :(得分:4)

我来到这里是因为我正在寻找一种方法来阻止polling API。

react docs确实涵盖了websocket案例,但不包括民意调查案例。

我的工作方式

// React component

React.createClass({
    poll () {
        if (this.unmounted) {
            return
        }
        // otherwise, call the api
    }
    componentWillUnmount () {
        this.unmounted = true
    }
})

它有效。希望它有所帮助

如果你们知道任何失败的测试用例,请告诉我这个=]

答案 4 :(得分:2)

我们建议您不要使用useState挂钩来跟踪组件是否已安装,因为每当更新状态时,react都会重新渲染整个组件组件,它也会触发useEffect或其他挂钩的执行。

function MyComponent(props: Props) {
  const isMounted = useRef(false)

  useEffect(() => {
    isMounted.current = true;
    return () => (isMounted.current = false)
  }, []);

  return (...);
}

export default MyComponent;

答案 5 :(得分:1)

相同的想法,但还有其他实现方式

/**
 * component with async action within
 * 
 * @public
 */
class MyComponent extends Component {
    constructor ( ...args ) {
        // do not forget about super =)
        super(...args);
        // NOTE correct store "setState"
        let originSetState = this.setState.bind(this);
        // NOTE override
        this.setState = ( ...args ) => !this.isUnmounted&&originSetState(...args);
    }
    /**
     * no necessary setup flag on component mount
     * @public
     */
    componentWillUnmount() {
        // NOTE setup flag
        this.isUnmounted = true;
    }
    /**
     *
     * @public
     */
    myCustomAsyncAction () {
        // ... code
        this.setState({any: 'data'}); // do not care about component status
        // ... code
    }

    render () { /* ... */ }
}

答案 6 :(得分:1)

如果您使用的是钩子:

function MyComponent(props: Props) {
  const [isMounted, setIsMounted] = useState<boolean>(false);

  useEffect(() => {
    setIsMounted(true);
  }, []);

  useEffect(() => {
    return () => {
      setIsMounted(false);
    }
  }, []);

  return (...);
}

export default MyComponent;

答案 7 :(得分:0)

我发现组件将被卸载,生成填充此var

if(!this._calledComponentWillUnmount)this.setState({vars});

答案 8 :(得分:0)

使用@DerekSoike答案,但是在我的情况下,使用useState来控制挂载状态不起作用,因为该状态在不需要时可以恢复

对我有用的是使用单个变量

myFunct是在setTimeout中调用的,我的猜测是,当同一组件在另一个页面中初始化该钩子时,它会恢复状态,从而导致内存泄漏再次出现

所以这对我不起作用

  const [isMounted, setIsMounted] = useState(false)

  useEffect(() => {
    setIsMounted(true)
    return () => setIsMounted(false)
  }, [])

  const myFunct = () => {
    console.log(isMounted) // not always false
    if (!isMounted) return
    // change a state
  }

这确实对我有用

  let stillMounted = { value: false }
  useEffect(() => {
    stillMounted.value = true
    return () => (stillMounted.value = false)
  }, [])

  const myFunct = () => {
    if (!stillMounted.value) return
    // change a state
  }

答案 9 :(得分:-1)

您可以使用:

myComponent.updater.isMounted(myComponent)

“ myComponent”是您的react组件的实例。 如果已安装组件,则返回“ true”,否则将返回“ false”。

  • 这是不支持的方法。您最好取消订阅任何异步/事件 在 componentWillUnmount 上。