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

IT技术 javascript reactjs
2021-01-24 02:00:09

我有一个用例,我需要卸载我的 React 组件。但在某些情况下,特定的 react 组件会被不同的函数卸载。因此,我需要在卸载之前检查该组件是否已安装。

6个回答

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

componentDidMount() { 
  this._ismounted = true;
}

componentWillUnmount() {
   this._ismounted = false;
}

这种维护自己state变量的模式在 ReactJS 文档中有详细说明:isMounted is an Antipattern

感谢您的提示...来自文档...只需在 componentDidMount 中将 _isMounted 属性设置为 true 并在 componentWillUnmount 中将其设置为 false ... 但是,使用 this.setState({mounted: false}); 可能触发太晚而无法阻止警告,因为状态更改不会立即发生 - 最好为此使用类属性...... this.mounted = false - 谢谢,这为我指明了正确的方向
2021-03-24 02:00:09
@KevinGhaboosi,不幸的是,只有提出问题的人才能接受这个作为答案
2021-03-25 02:00:09
@ danday74,是的,你是对的。当我写答案时,我可能没有抓住要点。如果有帮助,请考虑对答案进行投票
2021-04-07 02:00:09

我会建议您使用useRef钩子来跟踪组件是否已安装,因为每当您更新状态时,react 都会重新渲染整个组件,并且还会触发 useEffect 或其他钩子的执行。

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

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

  return (...);
}

export default MyComponent;

然后检查组件是否安装 if (isMounted.current) ...

使用stackoverflow.com/a/39767963/1783174获取类组件。将此用于挂钩。
2021-03-24 02:00:09
您的意思是说您确实建议使用useState而不是“不要”?因为您的解决方案似乎使用了它
2021-03-28 02:00:09

我认为 Shubham 的答案是 react 为需要转换代码以停止使用isMounted反模式的人建议的解决方法

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

Shubham 链接的文章提供了 2 个避免这种反模式的建议。您需要的取决于您在卸载组件时调用 setState 的原因。

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

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

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

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在链接的文章中阅读更多信息

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

只是为了指出仍然来这里的任何人。makeCancelable文章中引用方法是设置一个局部变量——就像舒巴姆的例子一样。没有办法真正取消 Promise。我很难理解为什么在其他地方设置一个布尔值会比在 React 组件中清楚地设置它更好。不过,关于取消订阅的观点是有效的。
2021-03-21 02:00:09
我的组件在对象的属性上设置代理。当该对象更新时,代理会调用setState以使属性和组件的状态同步。所以在这种情况下,这些建议是无关紧要的。
2021-03-22 02:00:09
想象一个帖子列表。每个帖子都是一个单独的组件,旁边(内部)有一个删除按钮。当用户单击按钮时,帖子设置isDeleting = true(禁用按钮),告诉父组件删除帖子(使用通过道具传递的回调),当他完成(另一个回调,但到帖子组件)时,它可能需要启用按钮。例如,发生 HTTP 错误时(帖子尚未删除)。也就是说,post 组件可能需要根据它是否仍然挂载而改变状态。有什么问题吗?
2021-04-05 02:00:09

另一种解决方案是使用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} />
    );
  }
}

使用@DerekSoike 回答,但是在我的情况下,useState用于控制安装状态不起作用,因为状态在不需要时复活了

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

myFunct在 a 中被调用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
  }
如果我们将 isMounted 状态更新为 true 或 false,它将重新加载功能组件,而不是我建议使用 let 变量。
2021-03-25 02:00:09
这有效,而之前的策略(在许多地方没有更新)...谢谢@GWorking
2021-03-31 02:00:09