Flux / React复合可重复使用组件

时间:2014-11-07 02:24:24

标签: reactjs reactjs-flux

我想做这样的事情

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调用的内容都需要通过

行动 - &gt; API - &gt;调度员 - &gt;商店 - &gt;成分

这使CountryAutoComplete与特定应用程序绑定,因为操作,Dispatcher和存储特定于App。使这个组件可以跨应用程序重用的最佳方法是什么?

1 个答案:

答案 0 :(得分:10)

你不应该在自动完成组件中进行任何ajax调用(因为你说你想让它可重用)。我通常将所有数据请求调用/ api用法放入一个单独的模块中,该模块使用promises来阻止多个请求

因此,我们的想法是让您的自动完成组件从父组件中获取选项/数据。该父组件最初可以从存储中获取数据,并侦听该存储中的任何更改事件,并在需要时更新其状态。将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实现imo应该与flux操作分开,它们应该只关注Web-API特定的东西,并且让flux actions / stores在数据流动时单独处理响应:

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