Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React Flux架构简介 #27

Open
kuitos opened this issue Sep 23, 2015 · 0 comments
Open

React Flux架构简介 #27

kuitos opened this issue Sep 23, 2015 · 0 comments

Comments

@kuitos
Copy link
Owner

kuitos commented Sep 23, 2015

React Flux架构简介

React简介请戳这里

Flux是什么

Flux是Facebook用来构建客户端web应用的应用架构。它利用单向数据流的方式来组合react中的视图组件。它更像一个模式而不是一个正式的框架,开发者不需要太多的新代码就可以快速的上手Flux。

Flux的核心部分

  1. dispatcher

    事件调度中心,flux模型的中心枢纽,管理着Flux应用中的所有数据流。它本质上是Store的回调注册。每个Store注册它自己并提供一个回调函数。当Dispatcher响应Action时,通过已注册的回调函数,将Action提供的数据负载发送给应用中的所有Store。应用层级单例!!

  2. store

    负责封装应用的业务逻辑跟数据的交互。

    • Store中包含应用所有的数据
    • Store是应用中唯一的数据发生变更的地方
    • Store中没有赋值接口---所有数据变更都是由dispatcher发送到store,新的数据随着Store触发的change事件传回view。Store对外只暴露getter,不允许提供setter!!禁止在任何地方直接操作Store。
  3. view

    • controller-view 可以理解成MVC模型中的controller,它一般由应用的顶层容器充当,负责从store中获取数据并将数据传递到子组件中。简单的应用一般只有一个controller-view,复杂应用中也可以有多个。controller-view是应用中唯一可以操作state的地方(setState())
    • view(UI组件) ui-component 职责单一只允许调用action触发事件,数据从由上层容器通过属性传递过来。
  4. 其他

    • action creators 作为dispatcher的辅助函数,通常可以认为是Flux中的第四部分。ActionCreators是相对独立的,它作为语法上的辅助函数以action的形式使得dispatcher传递数据更为便利。

How Flux(Unidirectional Data Flow) Works

  1. view --> actionCreators

    // Nav.jsx
    export default class Nav extends React.Component {
    
      _handleClick(nav) {
        NavActionCreators.clickNav(nav);
      }
    
      render() {
    
        let itemList = this.props.list.map((nav, index) => {
          return (
            <li className="index-menu-item" onClick={this._handleClick.bind(this, nav)} key={index}>
              <span>{nav.text}</span>
            </li>
          );
        });
    
        return (
          <nav className="index-menu">
            <ul className="index-menu-list">
              {itemList}
            </ul>
          </nav>
        );
      }
    }
  2. action dispatch

    // NavActionCreators.js
    export default {
    
      clickNav(nav){
    
        AppDispatcher.dispatch(
          {
            type: ActionTypes.CLICK_NAV,
            nav
          }
        );
      }
    };
  3. dispatcher --> store callback

    AppDispatcher.register(action => {
    
      switch (action.type) {
    
        // nav点击
        case ActionTypes.CLICK_NAV:
    
          IndexWebAPIUtils.getGiftList(_currentUserInfo.userId, action.nav.id)
            .then(function (giftList) {
    
              _currentGiftList = giftList;
              IndexStore.emitChange();
            });
    
          break;
    
        // no default
      }
    });
  4. store emitChange --> controller view --> setState

    export default class Index extends React.Component {
    
      constructor(props) {
        super(props);
        let currentUser = UserStore.getCurrentUser();
        this.state = IndexStore.getAll();
      }
    
      componentDidMount() {
        IndexStore.addChangeListener(this._onChange.bind(this));
      }
    
      componentWillUnmount() {
        IndexStore.removeChangeListener(this._onChange.bind(this))
      }
    
      _onChange() {
        this.setState(IndexStore.getAll());
      }
    
      render() {
    
        let state = this.state;
    
        return (
          <div className="page active">
            ...
            <Nav list={state.navList}/>
            ...
          </div>
        );
      }
    
    }

Flux vs MVVM

MVVM
  1. 简单的MVVM
  2. 复杂的MVC
Flux
  1. 复杂的Flux
Flux的优势
  1. 数据状态变得稳定同时行为可预测

    因为angular双向绑定的原因,我们永远无法知道数据在哪一刻处于稳定状态,所以我们经常会在angular中看到通过setTimeout的方式处理一些问题(其实有更优雅的解决方案,不在本次讨论之内)。同时由于双向绑定的原因,行为的流向我们也很难预测,当视图的model变多的时候,如果再加上一堆子视图依赖这些model,问题发生时定位简直是噩梦啊(这也是angular的错误信息那么不友好的原因,因为框架开发者也无法确定当前行为是谁触发的啊,绑定的人太多了...)。但是这里还是要强调一点就是,并不是说双向绑定就一定会导致不稳定的数据状态,在angular中我们通过一些手段依然可以使得数据变得稳定,只是双向绑定(mvvm)相对于flux更容易引发数据不稳定的问题。

  2. 所有的数据变更都发生在store里

    flux里view是不允许直接修改store的,view能做的只是触发action,然后action通过dispatcher调度最后才会流到store。所有数据的更改都发生在store组件内部,store对外只提供get接口,set行为都发生在内部。store里包含所有相关的数据及业务逻辑。所有store相关数据处理逻辑都集中在一起,避免业务逻辑分散降低维护成本。

  3. 数据的渲染是自上而下的

    view所有的数据来源只应该是从属性中传递过来的,view的所有表现由上层控制视图(controller-view)的状态决定。我们可以把controller-view理解为容器组件,这个容器组件中包含若干细小的子组件,容器组件不同的状态对应不同的数据,子组件不能有自己的状态。也就是,数据由store传递到controller-view中之后,controller-view通过setState将数据通过属性的方式自上而下传递给各个子view。

  4. view层变得很薄,真正的组件化

    由于2、3两条原因,view自身需要做的事情就变得很少了。业务逻辑被store做了,状态变更被controller-view做了,view自己需要做的只是根据交互触发不同的action,仅此而已。这样带来的好处就是,整个view层变得很薄很纯粹,完全的只关注ui层的交互,各个view组件之前完全是松耦合的,大大提高了view组件的复用性。

  5. dispatcher是单例的

    对单个应用而言dispatcher是单例的,最主要的是dispatcher是数据的分发中心,所有的数据都需要流经dispatcher,dispatcher管理不同action于store之间的关系。因为所有数据都必须在dispatcher这里留下一笔,基于此我们可以做很多有趣的事情,各种debug工具、动作回滚、日志记录甚至权限拦截之类的都是可以的。

Flux的困境

  1. 过多的样板代码

    flux只是一个架构模式,并不是一个已实现好的框架,所以基于这个模式我们需要写很多样板代码,代码量duang的一下子上来了。。不过好在目前已经有很多好用的基于flux的第三方实现,目前最火的属redux。

  2. dispatcher是单例

    dispatcher作为flux中的事件分发中心,同时还要管理所有store中的事件。当应用中事件一多起来事件时序的管理变得复杂难以维护,没有一个统一的地方能清晰的表达出dispatcher管理了哪些store。

  3. 异步处理到底写在哪里

    按flux流程,action中处理:依赖该action的组件被迫耦合进业务逻辑
    按store职责在store中处理:store状态变得不稳定,dispatcher的waitFor失效

  4. 至今还没有官方实现

写在最后

  • 前端摩尔定律:前端每18个月难度增加一倍

  • 没有银弹

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant