Flux是将异步数据提供给我的React.JS视图的正确解决方案

时间:2015-12-22 21:43:38

标签: javascript reactjs flux

我目前正在使用React.JS设计webapp的架构。在React中,数据流是单向的。有时(通常)我们希望在视图之间进行通信。 React通过焊剂解决了这个问题。到目前为止,我现在拥有存储(共享)数据的商店。

现在我想知道助焊剂是否也是解决这个老问题的正确方法: 一个视图,比如表需要来自应该呈现的服务器的数据。如果这是一个愚蠢的问题,我对React经验不足,请原谅我,但是flux也是从服务器获取数据并将其解析为注册视图的正确解决方案吗?如果是这样,是否有最佳实践来处理异步数据?如果没有,那么从服务器获取反应视图的数据的适当方法是什么?

我实际上不希望视图调用数据。在我看来,观点应该尽可能愚蠢......

2 个答案:

答案 0 :(得分:3)

  

.. flux也是从服务器获取数据的正确解决方案   将其解析为已注册的观点?

你可以用助焊剂做到这一点。通量约为Action Creators。在磁通体系结构中,我们的想法是你有Controller ViewStore注册自己。 Controller View是你的智能组件,它从商店获取状态,通常它呈现子组件,哑组件,它通过(某些)陈述作为它的孩子(ren)的属性。

enter image description here

例如,当您从服务器获取数据时,需要触发Action Creator,然后此Action Creator将调用执行实际请求的Web API实用程序。成功后,Web API实用程序将调用服务器操作创建程序,该服务器操作创建程序将调度包含从服务器接收的有效内容的操作。然后,任何已注册的商店都将处理此操作并发出更改事件。这样,当Store的数据发生变化时,任何对商店感兴趣的Controller View都会收到通知。 Controller View将更新它的状态并重新渲染自身和任何子(ren)以显示正确的数据。

这意味着你可以调用一个Action Creator,例如从控制器视图的componentDidMount中获取服务器中的数据(注意这个钩子只执行一次!)。 最初,Controller View会向商店询问数据并获取一个空数组,该数组将被设置为Controller View的状态,Controller View将呈现空的状态。然后,在获取数据后,Controller View(由Store通知的人)将再次从Store检索数据,现在它不会为空。 Controller View相应地更新它的状态,触发重新渲染并显示适当的数据。

这个本质是在这个最小(伪)代码中捕获的:

// Action Creator: actions/data.js
import { fetchData } from '../utils/server';

export function fetch() {
  fetchData();
}

// Server Action Creator: actions/data-server.js
import dispatcher from '../dispatcher';

export function receiveData(data) {
  dispatcher.dispatch({
    type: 'RECEIVE_DATA',
    payload: data
  });
}

// Web API Utility: utils/server.js
import request from 'request';
import { receiveData } from '../actions/data-server';

export function fetchData() {
  request.get('https://api.com/v1/data', receiveData);
}

// Store: stores/store.js
import dispatcher from '../dipatcher';
import { EventEmitter } from 'events';

const CHANGE_EVENT = 'change';
let __data__ = [];

const Store = Object.assign({}, EventEmitter.prototype, {
  emitChange () {
    this.emit(CHANGE_EVENT);
  },

  addChangeListener (callback) {
    this.on(CHANGE_EVENT, callback);
  },

  removeChangeListener (callback) {
    this.removeListener(CHANGE_EVENT, callback);
  },

  getData () {
    return __data__;
  }
});

Store.dispatchToken = dispatcher.register(function (action) {
  switch (action.type) {
    case 'RECEIVE_DATA':
      __data__ = action.payload;
      Store.emitChange();
      break;
  }
});

export default Store;

// Controller View: components/List.jsx
import React from 'react';
import Store from '../stores/Store');
import { fetch } from '../actions/data';

var __getState = function () {
  return {
    data: Store.getData()
  };
};

export default React.createClass({
  getInitialState () {
    return __getState();
  },

  componentWillMount () {
    fetch();
  },

  componentDidMount () {
    Store.addChangeListener(this._onChange);
  },

  componentWillUnMount () {
    Store.removeChangeListener(this._onChange);
  },

  _onChange () {
    this.setState( __getState() );
  },

  render () {
    const { data } = this.state;

    return (
      <div className="list">
        <ul>
          { data.map(dataItem => <li>{ dataItem.name }</li> )}
        </ul>
      </div>
    );
  }
});

查看更详细的助焊剂示例here

  

我实际上不希望视图调用数据。在我看来a   视图应该尽可能愚蠢......

区分智能 dumb 组件是一种很好的做法。这个想法是智能组件保持状态和调用操作,而哑组件不依赖于应用程序的其余部分。这样可以明确区分关注点,从而实现组件的更好的可重用性和可测试性。阅读更多相关信息here

除了助焊剂之外,还有一些有趣的选择。例如,有redux。它使用单个不可变状态Object(即Store),其中reducer(纯函数)仅允许通过操作修改应用程序状态。

如果你主要是从服务器上渲染和渲染只读数据,那么一定要查看react-refetch

答案 1 :(得分:2)

执行此操作的常用方法是在视图代码的componentDidMount()方法中初始化异步调用,并正确呈现它。

对于不同的通量实现,代码可能会有所不同,但您可以理解

getInitialState() {
  return {
    rows: MyStore.getState().rows
  }
}

componentDidMount() {
  this.listenTo(MyStore, this.onChange)
  MyActions.fetchData()
}

onChange() {
  this.setState(this.getInitialState())
}
....


render() {
  if (!this.state.rows) {
    return <span />
  }

  return <Table rows={this.state.rows}>
}

至于容器组件,完全取决于您使用它。