小编典典

助焊剂/反应复合物可重复使用组件

reactjs

我想做这样的事情

var App = React.createClass({
    render: function() {
        return (
            <CountryAutoComplete />
        )
    }
});

不同的应用

var App2 = React.createClass({
    render: function() {
        return (
            <CountryAutoComplete />
        )
    }
});

这是一个简单的自动完成功能(不是整个文件)

var AutoComplete = React.createClass({
    componentDidMount: function() {
        $(this.getDOMNode()).typeahead(this.props);
    },
    render: function() {
        return (
            <input type="text" class="typeahead" onChange={this.props.onChange} />
        );
    }
});

CountryAutoComplete就像这样的东西是自包含的。

var CountryAutoComplete = React.createClass({
    search: function(country, process) {
        // Make an ajax call and return the data. No other components needed
        $.ajax({
            url: '/country' + '?search=' + country
        }).then(process);
    },
    render: function() {
        return (
            <AutoComplete onChange={this.props.onChange} source={this.search} />
        );
    }
});

根据Flux文档,看起来需要API调用的所有内容都需要经过

操作-> API->调度程序->存储->组件

这使得CountryAutoComplete绑定到特定的应用程序,因为操作,分派器和存储都特定于该应用程序。使该组件在应用程序之间可重用的最佳方法是什么?


阅读 303

收藏
2020-07-22

共1个答案

小编典典

您不应该在自动完成组件中进行任何Ajax调用(因为您说过要使其可重用)。我通常将所有数据请求调用/
api用法放在一个单独的模块中,该模块使用promise防止多个请求

因此,想法是让您的自动完成组件从父组件获取选项/数据。该父组件可以最初从存储中获取数据,并监听该存储中的任何更改事件,并在需要时更新其状态。将其this.state.options(或用于选项的任何状态)传递为自动完成的道具。用户键入内容时,对查询发出操作。相应地,该操作应调用API和分派器,更新商店,并为商店发出更改事件。您的父组件将分别更新其状态,并且将作为道具流向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];
    }
}

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
2020-07-22