【问题标题】:React warning about setState in unmounted component对未安装组件中的 setState 做出反应警告
【发布时间】:2018-10-06 08:31:35
【问题描述】:

我收到此错误:

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 方法。我真的不知道为什么这个警告不断弹出,任何信息都会有所帮助。


2018 年 5 月 23 日更新:

为了摆脱错误并且仍然有 props 传递,我做了两件事:

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

【问题讨论】:

  • 您可以通过将 ComponentWillMount 更改为 ComponentDidMount 来尝试相同的方法吗?
  • 我做了,但它抛出了一个错误,因为它需要在渲染组件之前知道它们是否经过身份验证。
  • 好的,在这种情况下,您可以从那里删除 history.push 并设置一个标志以显示其未经身份验证并在未经身份验证的情况下在 render() 中返回 。 histoty.push 将尝试卸载未安装的组件,因此出现错误。
  • 感谢您的帮助。如 React Router 4 文档中所述,我最终使用渲染而不是组件,并且错误消失了。
  • 那是什么意思?你能写一个你的代码的简短例子吗?我没有找到任何关于这个文档的观点

标签: reactjs


【解决方案1】:

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

查看此类错误的一个好习惯是绘制您的应用流程并查看您何时调用setState

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

此生命周期以前被命名为 componentWillMount。该名称将继续使用到版本 17。使用 rename-unsafe-lifecycles 代码模块自动更新您的组件。

Reactjs component documentation

【讨论】:

    【解决方案2】:

    我遇到了类似的问题,但我确实弄清楚了背后的原因,所以这里是我遇到这个错误的代码的 sn-p。

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

    正如你在code-sn-p中看到的,我在做

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

    在设置状态之前。

    this.setState({ showLoader: false });
    

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

    解决方法:

    通过放置

    this.setState({ showLoader: false });
    

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

    我希望这会有所帮助。

    【讨论】:

      猜你喜欢
      • 2018-03-20
      • 2018-01-29
      • 1970-01-01
      • 1970-01-01
      • 2016-10-01
      • 2016-02-22
      • 2019-01-07
      • 2019-08-15
      • 1970-01-01
      相关资源
      最近更新 更多