Ответ 1
Вы не должны делать какие-либо вызовы ajax в компоненте автозаполнения (так как вы сказали, что хотите сделать его многоразовым). Я обычно помещаю все запросы запроса данных /api в отдельный модуль, который использует promises для предотвращения нескольких запросов
Итак, идея состоит в том, чтобы просто добавить ваш компонент автозаполнения к параметрам/данным из родительского компонента. Этот родительский компонент может сначала получить данные из хранилища, а также прослушать любые события изменений в этом хранилище и, при необходимости, обновить его состояние. Передайте этот this.state.options
(или любое другое состояние, которое вы используете для параметров) в качестве опоры для автозаполнения. Когда пользователь что-то набирает, выпустите действие с запросом. Это действие по очереди должно вызывать API и диспетчер, обновлять хранилище и испускать событие изменения для хранилища. Ваш родительский компонент будет обновлять свое состояние соответственно, и это будет передаваться компоненту автозаполнения в качестве опоры.
Так что-то вроде этого:
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 imo должна быть отделена от действий потока, они должны быть связаны только с конкретными вещами Web-API и просто позволяют действиям/хранилищам потока обрабатывать ответы отдельно как потоки данных:
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