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

时间:2018-04-25 18:52:43

标签: reactjs

我收到此错误:

  

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

但我没有使用componentWillUnMount方法。

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

这是路线:

<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 }
          }}
        />
      )
    }
  />
);

2 个答案:

答案 0 :(得分:7)

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

看到这类错误的好习惯是吸引您的应用流程,看看您何时致电setState

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

  

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

     

Reactjs component documentation

答案 1 :(得分:2)

我有一个类似的问题,但是我确实弄清楚了这个问题的原因,所以这是我遇到此错误的代码片段。

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 });

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

解决方案:

通过放置

this.setState({ showLoader: false });

this.props.history.push("profile");上方的问题已解决。

我希望这会有所帮助。