【问题标题】:Flux/React Complex Reusable ComponentFlux/React 复杂的可重用组件
【发布时间】:2015-01-03 18:13:45
【问题描述】:

我想做这样的事情

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

actions -> API -> Dispatcher -> stores -> 组件

这使得 CountryAutoComplete 绑定到特定应用,因为操作、调度程序和商店是特定于应用的。使此组件可跨应用重用的最佳方法是什么?

【问题讨论】:

    标签: reactjs reactjs-flux


    【解决方案1】:

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

    因此,想法就是让您的自动完成组件从父组件获取选项/数据。该父组件最初可以从存储中获取数据,并侦听该存储中的任何更改事件,并在需要时更新其状态。将 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
    

    【讨论】:

    • 感谢您提供如此详细的答案。这很有帮助。组件不应该保持状态或直接调用 API 吗?每次都使用这个组件似乎有很多样板。调度程序特定于应用程序。
    • well react 是一个视图,因此我认为任何 ajax 请求(api 调用)都应该与 react 组件分开。它可能是很多样板,但它使组件保持可重用和隔离。这里有一篇关于这个数据流的写得比较详细的文章:code-experience.com/…
    • 因为自动完成依赖于ajax,而ajax属于独立的组件/调度器,任何依赖ajax的组件都不能真正成为一个独立的、可重用的组件?将 ajax 包含在自动完成组件中并让组件发出应用程序的调度程序和存储可以侦听的事件会有什么问题?
    • 如何保持对相关 HTML 元素的关注?
    猜你喜欢
    • 2017-12-10
    • 2016-03-02
    • 2016-02-25
    • 2017-10-05
    • 2017-04-07
    • 2021-10-01
    • 2016-08-17
    • 2015-07-09
    • 2015-11-09
    相关资源
    最近更新 更多