编辑:检出git存储库以获取最小示例:https://github.com/maximilianschmitt/blind-lifecycle

我有一个组件RequireUser,试图确保用户已登录,否则将不呈现其子级。它的父组件App应该知道是否需要用户,并在需要时呈现登录表单。

问题是,App组件会在RequireUser组件之后像这样在树中安装:

App
  RequireUser
    SomeOtherComponent


RequireUsercomponentDidMount中,我正在触发将requireLoginUserStore变量设置为loginRequired的操作true

这不会更新父组件(App),因为尚未安装它,因此不能将更改注册到存储中。

class RequireUser extends React.Component {
  constructor() {
    super();
    this.state = alt.stores.UserStore.getState();
  }

  componentDidMount() {
    this.unlisten = alt.stores.UserStore.listen(this.setState.bind(this));
    if (!this.state.requireUser) {
      UserActions.requireUser();
      // using setTimeout will work:
      // setTimeout(() => UserActions.requireUser());
    }
  }

  componentWillUnmount() {
    this.unlisten();
  }

  render() {
    if (this.state.requireUser) {
      return <div>I have required your user</div>;
    }

    return <div>I will require your user</div>;
  }
}

class App extends React.Component {
  constructor() {
    super();
    this.state = alt.stores.UserStore.getState();
  }

  componentDidMount() {
    this.unlisten = alt.stores.UserStore.listen(this.setState.bind(this));
  }

  componentWillUnmount() {
    this.unlisten();
  }

  render() {
    return (
      <div>
        <div>User required? {this.state.requireUser + ''}</div>
        <RequireUser />
      </div>
    );
  }
}


输出:


  需要用户吗?假
  
  我已要求您的用户


如果我在setTimeout中使用RequireUser,则App会接收状态更改和呈现,但仅在闪烁之后:


  需要用户吗?真正
  
  我已要求您的用户


我感觉到我在做的是反模式,对于提出比使用setTimeout闪烁更优雅的解决方案的建议,我将不胜感激。谢谢!

最佳答案

我建议的答案是将其添加到App组件中:

componentDidMount() {
    // setup listener for subsequent changes
    alt.stores.UserStore.listen(this.onChange);

    // grab the current state now that we're mounted
    var userStoreState = alt.stores.UserStore.getState();
    this.setState(userStoreState);
}


无法避免双重渲染。您的RequireUser组件已经执行了两个渲染。


RequireUser的初始呈现
componentDidMount()回调


派遣行动

UserStore接收调度的动作并更新其状态


发出变更通知

RequireUser根据状态更改设置状态
二次渲染RequireUser


但是您的代码库仍然被认为是Flux,并且确实遵循针对React应用程序的模式。本质上,您有一个加载状态...一种实际上不知道是否需要用户的状态。根据UserActions.requireUser()的功能,可能需要也可能不需要。

您可能会考虑重构

如果将RequireUser重写为仅查看组件,则可以修复双重渲染。这意味着既没有侦听器,也没有内部设置状态。这个组件只是根据传入的props渲染元素。实际上,您的RequireUser组件都是:

class RequireUser extends React.Component {
    render() {
        if (this.props.requireUser) {
            return <div>I have required your user</div>;
        }
        return <div>I will require your user</div>;
     }
}


然后,您将使您的App组件成为控制器视图。在此处添加了侦听器,并且状态的任何更改都通过props向下传播。现在我们可以在componentWillMount回调中进行设置。这给了我们单一的渲染行为。

class App extends React.Component {
    (other lifecycle methods)

    componentWillMount() {
        if (!this.state.requireUser) {
            UserActions.requireUser();
        }
        var userStoreState = alt.stores.UserStore.getState();
        this.setState(userStoreState);
    }

    componentDidMount() {
        (same as above)
    }

    render() {
        return (
            <div>
                <div>User required? {this.state.requireUser + ''}</div>
                <RequireUser requireUser={this.state.requireUser} />
            </div>
       );
    }
}


Flux体系结构和控制器视图/视图:https://facebook.github.io/flux/docs/overview.html#views-and-controller-views

关于javascript - React + Alt:生命周期差距,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/33550763/

10-11 06:40