您不应该在自动完成组件中进行任何 ajax 调用(因为您说过要使其可重用)。我通常将所有数据请求调用/API 使用放入一个单独的模块中,该模块使用 Promise 来防止多个请求
因此,我们的想法是让自动完成组件从父组件获取选项/数据。该父组件最初可以从存储中获取数据,并侦听该存储中的任何更改事件,并在需要时更新其状态。通过那个this.state.options
(或您用于选项的任何状态)作为自动完成的支持。当用户键入内容时,通过查询发出一个操作。该操作依次调用 API 和 Dispatcher、更新存储并为存储发出更改事件。您的父组件将分别更新其状态,并将作为 prop 流向 AutoComplete 组件。
所以像这样:
var App = React.createClass({
getInitialState: function() {
return {
// default results/data?
data : Store.getResults('')
};
},
storeChangeListener: function(newData) {
this.setState({
data: newData
});
},
componentDidMount: function() {
this.listenTo(Store, this.storeChangeListener);
},
onChange: function(query) {
// on search change
Actions.getResults(query);
},
render: function() {
return (
<AutoComplete data={this.state.data} onChange={this.onChange} />
);
}
});
在商店里,有这样的东西:
var countryAPI = require('./countryAPI')
var Store = {
getResults: function(query) {
// check cache if any? otherwise make call
if(this.cache[query]) {
return this.cache[query];
} else {
countryAPI.search(query).then(this.update);
}
},
update: function(data) {
AppDispatcher.dispatch({
type: "DATA_FROM_SERVER",
payload: {id: query, data: result}
})
},
handleDataFromServer: function(action) {
//store into cache/store
this.cache[action.payload.id] = action.payload.result;
this.emit("change"); // re-render app on whoever is listening to this store
}
}
和你的 api 例如
var countryAPI = {
search: function(query) {
// check to make sure this promise isnt called before
if(!this.allPromises[query]) {
this.allPromises[query] = $.ajax({
url: '/country' + '?search=' + country
})
}
return this.allPromises[query];
}
}
总而言之,实际的 API 实现应该与 Flux 操作分开,它们只应该关心 Web-API 特定的内容,并让 Flux 操作/存储作为数据流单独处理响应:
Component --> Listens to Store
--> Calls Load Action --> Show Pending State/Optimistic Updates --> Dispatcher --> Store --> changeEvent (Component will be listening and be updated)
--> countryAPI.load()
onLoadSuccess --> Dispatcher --> Store --> changeEvent --> Component
onLoadError --> Dispatcher --> Store --> changeEvent --> Component