我目前正在使用React.JS设计webapp的架构。在React中,数据流是单向的。有时(通常)我们希望在视图之间进行通信。 React通过焊剂解决了这个问题。到目前为止,我现在拥有存储(共享)数据的商店。
现在我想知道助焊剂是否也是解决这个老问题的正确方法: 一个视图,比如表需要来自应该呈现的服务器的数据。如果这是一个愚蠢的问题,我对React经验不足,请原谅我,但是flux也是从服务器获取数据并将其解析为注册视图的正确解决方案吗?如果是这样,是否有最佳实践来处理异步数据?如果没有,那么从服务器获取反应视图的数据的适当方法是什么?
我实际上不希望视图调用数据。在我看来,观点应该尽可能愚蠢......
答案 0 :(得分:3)
.. flux也是从服务器获取数据的正确解决方案 将其解析为已注册的观点?
你可以用助焊剂做到这一点。通量约为Action Creators。在磁通体系结构中,我们的想法是你有Controller View用Store注册自己。 Controller View是你的智能组件,它从商店获取状态,通常它呈现子组件,哑组件,它通过(某些)陈述作为它的孩子(ren)的属性。
例如,当您从服务器获取数据时,需要触发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}>
}
至于容器组件,完全取决于您使用它。