Flux/React Complex Reusable Component

拜拜、爱过 提交于 2019-12-02 20:59:39

You shouldn't be making any ajax calls in the autocomplete component (since you said you want to make it reusable). I usually put all the data request calls/api usage into a separate module that uses promises to prevent the multiple requests

So the idea then is to just have your autocomplete component get the options/data from a parent component. That parent component can get the data from store initially, and listen for any change events in that store, and update its state if needed. Pass that this.state.options (or whatever state you're using for the options) as a prop to AutoComplete. When a user types something, emit an action with the query. That action in turns should call the API and Dispatcher, updates the store, and emits a change event for the store. Your parent component will update its state respectively, and that will flow to the AutoComplete component as prop.

So something like this:

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} />
        );
    }
});

And in store, something like this:

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
    }
}

and your api for example

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];
    }
}

To sum it up, the actual API implementation imo should be separated from flux actions, they only should be concerned with Web-API specific stuff and just let flux actions/stores handle the responses separately as data flows:

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
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!