Flux/React Complex Reusable Component

后端 未结 1 506
一生所求
一生所求 2021-02-03 10:37

I want to do something like this

var App = React.createClass({
    render: function() {
        return (
            
        )
            


        
相关标签:
1条回答
  • 2021-02-03 11:17

    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
    
    0 讨论(0)
提交回复
热议问题