【问题标题】:How to use componentWillUnmount in React Native?如何在 React Native 中使用 componentWillUnmount?
【发布时间】:2019-06-14 19:11:57
【问题描述】:
  componentDidMount () {
        this.showPosts();
  }

  showPosts = async () => {

    var userID = await AsyncStorage.getItem('userID');

    fetch(strings.baseUri+"getPostWithUserID", {
        method: 'POST',
        headers: {
           Accept: 'application/json',
           'Content-Type': 'application/json'
        },
        body: JSON.stringify({ 
            "user_id": userID
        })
        })
        .then((response) => response.json())
        .then((responseJson) => {

          this.setState({show: false}); // If I comment this line, then I don't get the warning.

        })
        .catch((error) => {
            console.error(error);
        });
  }

如何使用 componentWillUnmount,因为我收到以下警告。 当我使用 componentWillUnmount 时,有没有办法可以将 setState 显示为 true? Warning

【问题讨论】:

标签: reactjs react-native


【解决方案1】:

您在代码中混合了一些东西。当您使用 this.showPosts() 时,您正在使用 await 但未调用 await。您也没有将await 包装在try/catch 中,因为await 可以抛出。

有几种方法可以解决在未安装组件上设置状态的问题。最简单的(尽管它是一种反模式)是在componentDidMountcomponentWillUnmount 中设置一个变量来跟踪组件的安装状态。

让我们重构你的代码,让它更有意义

这就是您的componentDidMountcomponentWillUnmount 现在的样子。

async componentDidMount () {
  this._isMounted = true;
  await this.showPosts();
}

componentWillUnmount () {
  this._isMounted = false;
}

更新showPosts,使其纯粹是async/await

showPosts = async () => {
  try {
    var userID = await AsyncStorage.getItem('userID');
    let response = await fetch(strings.baseUri + 'getPostWithUserID', {
      method: 'POST',
      headers: {
        Accept: 'application/json',
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        'user_id': userID
      })
    });

    let responseJson = await response.json();
    if (this._isMounted) {
      this.setState({show: false});
    }
  } catch (err) {
    console.error(error);
  }
}

或者,如果我们使用您当前的 showPosts 实现,它看起来像这样,但修复了 await 周围缺少 try/catch 的问题。

showPosts = async () => {
  try {
    var userID = await AsyncStorage.getItem('userID');

    fetch(strings.baseUri + 'getPostWithUserID', {
      method: 'POST',
      headers: {
        Accept: 'application/json',
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        'user_id': userID
      })
    })
      .then((response) => response.json())
      .then((responseJson) => {
        if (this._isMounted) {
          this.setState({show: false}); // If I comment this line, then I don't get the warning.
        }
      })
      .catch((error) => {
        console.error(error);
      });
  } catch (err) {
    console.warn(err);
  }
}

另一种方法是在做出承诺后立即取消承诺。这篇文章以某种方式解释了如何做到这一点https://reactjs.org/blog/2015/12/16/ismounted-antipattern.html

【讨论】:

  • 非常感谢@Andrew。它终于对我有用。但我有一个问题,为什么我们要使用this._isMounted 来制作变量。我的意思是你能告诉我你用这种方式做变量是在哪里写的。
  • 另外我刚刚检查了 isMounted 在调用 setState() 之前确实消除了警告。所以你给我的解决方案,是正确的方法还是 hack?
  • this.isMounted() 已弃用,并将在将来的某个时间删除。最好不要使用已弃用的函数。
  • 不,我的意思是整体解决方案是否正确?因为文章说if (this.isMounted()) { this.setState({ }) }这消除了警告
  • 是的,这是一个有效的解决方案。文章说: 对于任何升级代码以避免 isMounted() 的人来说,一个简单的迁移策略是自己跟踪挂载状态。只需在 componentDidMount 中将 _isMounted 属性设置为 true,然后在 componentWillUnmount 中将其设置为 false,然后使用此变量来检查组件的状态。 因此,我们所做的就是避免使用已弃用的 API 并使用有效的解决方案。
【解决方案2】:

您可以使用一些内部组件对象属性作为 - isComponentMounted,然后在异步操作回调期间检查它。

【讨论】:

  • 怎么做?
  • 你需要自己定义它,然后用生命周期方法控制它 - componentDidMount () { this.isComponentMounted = true }, componentWillUnmount () { this.isComponentMounted = false }
【解决方案3】:

你可以检查组件是否以这种方式挂载,然后检查你的异步函数中的这个变量,看看你是否仍然可以运行该函数或取消它:

componentDidMount() { 
  this.mounted = true;
}

componentWillUnmount() {
  this.mounted = false;
}

async asyncFunction {
  if(this.isMounted){
    setState(....);
  }else{
    return;
  }
}

【讨论】:

  • 问题是如果组件未安装,如何防止在异步操作中设置状态 - 所以我会说仍然相关
  • @Mtg Kha Jeskai 是的,我知道。无论如何我可以阻止这个警告吗?
  • 这里 -> stackoverflow.com/questions/49906437/… 你有可能的方法来防止它
  • if(this.isMounted) 应该正好在 setState 之前而不是在 fetch 之前
  • 它给了我一个警告,isMounted 已被弃用。
【解决方案4】:

在没有构造函数初始状态的情况下在 componentDidMount 中设置状态不是一个好主意,因为它会触发额外的渲染,这可能会导致性能问题。

来自官方文档:

您可以立即在 componentDidMount() 中调用 setState()。它会触发额外的渲染,但会在浏览器更新屏幕之前发生。这保证了即使在这种情况下 render() 将被调用两次,用户也不会看到中间状态。请谨慎使用此模式,因为它通常会导致性能问题。在大多数情况下,您应该能够在 constructor() 中分配初始状态。但是,对于模态框和工具提示等情况,当您需要在渲染取决于其大小或位置的内容之前测量 DOM 节点时,它可能是必要的。

https://reactjs.org/docs/react-component.html#componentdidmount

但这又回到了为什么要使用 componentWillUnmount?用于注销事件、推送通知、清理资源。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-09-11
    • 2020-06-25
    • 1970-01-01
    • 2019-02-17
    • 2019-10-26
    • 1970-01-01
    • 1970-01-01
    • 2020-05-13
    相关资源
    最近更新 更多