React + Alt:生命周期差距

时间:2015-11-05 17:14:39

标签: javascript reactjs flux alt.js

编辑:查看git存储库以获取最佳示例: https://github.com/maximilianschmitt/blind-lifecycle

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

问题是,App组件安装在树中的RequireUser组件之后,如下所示:

App
  RequireUser
    SomeOtherComponent

RequireUser的{​​{1}}我触发了一项操作componentDidMount,将requireLogin的{​​{1}}变量设置为UserStore。< / p>

这不会更新父组件(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会收到状态更改并呈现,但仅在闪烁之后:

  

需要用户吗?真

     

我已经要求您的用户

我感觉我正在做的是一个反模式,我会感谢更优雅的解决方案的建议,而不是使用setTimeout闪烁。谢谢!

2 个答案:

答案 0 :(得分:1)

我建议的答案是将其添加到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组件已执行两次渲染。

  1. RequireUser的初始渲染
  2. componentDidMount()回调
    • 分派行动
  3. UserStore接收调度的操作并更新其状态
    • 发出更改通知
  4. RequireUser根据状态更改设置状态
  5. 第二次渲染RequireUser
  6. 但您的代码库仍被视为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>;
         }
    }
    

    然后,您将使您的应用程序组件成为 controller-view 。这里添加了监听器,对状态的任何更改都通过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

答案 1 :(得分:1)

只有在构建每个组件时,您的组件才会从您的商店一次获取states。这意味着您的组件中的statesstates

中的store同步

您需要在安装时在组件上设置store侦听器,以便从store和最新states中检索触发器。使用setState()更新组件内的states,以便再次调用render()以呈现最新的states