在已卸载的组件中发出有关setState的警告

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在已卸载的组件中发出有关setState的警告相关的知识,希望对你有一定的参考价值。

我收到这个错误:

warning.js:33警告:无法在卸载的组件上调用setState(或forceUpdate)。这是一个无操作,但它表示应用程序中存在内存泄漏。要修复,请取消componentWillUnmount方法中的所有订阅和异步任务。

但我没有使用componentWillUnMount方法。

我正在使用HOC来确保用户在访问其/ account帐户之前已通过身份验证。

这是路线:

<StyleRoute props={this.props} path="/account" component= 
{RequireAuth(Account)} />

其中RequireAuth是HOC。这是HOC:

 import { withRouter } from 'react-router';

export default function RequireAuth(Component) {

  return class AuthenticatedComponent extends React.Component {

    componentWillMount() {
      this.checkAuth();
    }

    checkAuth() {
      if ( ! this.props.isAuthenticated) {
        this.props.history.push(`/`);
      }
    }

    render() {
      return this.props.isAuthenticated
        ? <Component { ...this.props } />
        : null;
    }

  }

  return withRouter(AuthenticatedComponent);
}

代码按预期工作,但是在呈现/ account时我收到了错误。正如您所注意到的,我的直接代码中没有任何地方存在componentWillUnMount方法。我真的不知道为什么这个警告不断出现,任何信息都会有所帮助。


更新5/23/18:

为了摆脱这个错误并且还有道具传递下来,我做了两件事:

1)我选择在父App组件中使用两个更高阶的函数,而不是使用HOC。一个高阶函数用于传递道具,另一个用于检查身份验证。我无法传递除浏览器历史之外的任何道具,因此下面是renderProps函数。

renderProps = (Component, props) => {
  return (
      <Component {...props} />
    );
}

checkAuth = (Component, props) => {
    if (props.isAuthenticated) {
        return <Component {...props} />
    }
    if (!props.isAuthenticated) {
        return <Redirect to='/' />
    }
}

2)要使用这些,我必须在我的路线中使用渲染,而不是组件。

//I could pass props doing this, sending them through the above functions
<Route exact path="/sitter-dashboard" render={ () => this.checkAuth(SitterDashboard, this.props) } />
<Route exact path={"/account/user"} render={() => this.renderProps(User, this.props)} />

//I couldn't pass props doing this
<Route {...this.props} exact path="/messages" component={Messages} />

这是路由器与组件的文档,作为路由渲染方法:https://reacttraining.com/react-router/web/api/Route/route-render-methods

另外,这里是对Stack Overflow的一个很好的解释

最后,我使用了React Router 4文档中的代码作为我上面所做的模板。我确信下面的内容更清晰,但我还在学习,我所做的对我来说更有意义。

const PrivateRoute = ({ component: Component, ...rest }) => (
<Route
  {...rest}
  render={props =>
  fakeAuth.isAuthenticated ? (
       <Component {...props} />
      ) : (
        <Redirect
          to={{
            pathname: "/login",
            state: { from: props.location }
          }}
        />
      )
    }
  />
);
答案

我之前有同样的错误,它是由一个使用ref标签的组件生成的,并且有一些手动操作。

看到这类错误的好习惯是吸引你的应用流程,看看你何时打电话给setState

如果我是你,我会改变的另一件事是componentDidMount而不是componentWillMount来检查一些数据。考虑到fb已弃用此功能。

此生命周期之前名为componentWillMount。该名称将继续有效,直到版本17.使用rename-unsafe-lifecycles codemod自动更新组件。

Reactjs component documentation

另一答案

我有一个类似的问题,但我确实找出了相同的原因,所以这里是我遇到这个错误的代码片段。

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.

原因:

   this.setState({ showLoader: true });
    const { username } = this.state;
    const URL = `https://api.github.com/users/${username}`;
    try {
      const { data } = await axios(URL);
      this.props.apiData(data);
      this.props.history.push("profile");
    } catch (e) {
      console.error(e);
    }
    this.setState({ showLoader: false });

正如您在代码片段中看到的那样,我正在做

this.props.history.push("profile");

在设置状态之前。

this.setState({ showLoader: false });

然后,在这种情况下,错误似乎是合法的,因为我重定向到另一个组件,然后在我之前的组件上设置状态。

解:

放置

this.setState({ showLoader: false });

this.props.history.push("profile");上方解决了这个问题。

我希望这有帮助。

以上是关于在已卸载的组件中发出有关setState的警告的主要内容,如果未能解决你的问题,请参考以下文章

为啥 FxCop 会在此 C# 代码中发出有关溢出 (CA2233) 的警告?

“警告:setState(...):只能更新已安装或已安装的组件”是啥意思?

React 警告:setState(...) 只能更新已安装或正在安装的组件

如何解决反应原生 EventEmitterListener 警告

ReactJS , setState 发出 onChange 事件

在未安装的组件上调用 setState() [重复]