12

我想做这样的事情

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 绑定到特定的应用程序,因为操作、调度程序和商店是特定于应用程序的。使该组件可跨应用程序重用的最佳方法是什么?

4

1 回答 1

10

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

因此,想法是让您的自动完成组件从父组件获取选项/数据。该父组件最初可以从存储中获取数据,并侦听该存储中的任何更改事件,并在需要时更新其状态。将它this.state.options(或您用于选项的任何状态)作为道具传递给 AutoComplete。当用户键入内容时,发出带有查询的操作。该操作应依次调用 API 和 Dispatcher、更新存储并为存储发出更改事件。您的父组件将分别更新其状态,并将作为道具流向 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 应该与通量操作分开,它们只应该关注 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
于 2014-11-08T00:29:58.687 回答