【问题标题】:React component with ajax call - life-cycle使用 ajax 调用反应组件 - 生命周期
【发布时间】:2016-05-01 16:06:34
【问题描述】:

所以我有一个使用 React with Ajax 调用的有趣案例。

为了把它放在上下文中,我有一个带有 3 个标签的手风琴。初始化 Accordion react 组件后,我首先打开了第一个选项卡,其余选项卡关闭。 每个选项卡的主体中都有所谓的 DictionaryCall 组件,如下所示:

return class DictionaryCall extends React.Component {

        constructor (props) {
            super();
            this.state = {
                word: '',
                data: [],
                error: false,
                nodata: false,
                initialLoaded: props.load
            }
        }

        componentDidMount () {
            if(this.state.initialLoaded){
                this.callAjax();
            }
        }

        componentWillReceiveProps (nextProps) {
            if(nextProps.load){
                this.setState({initialLoaded: true});
                this.callAjax();
            }
        }

        callAjax () {
            $.ajax({
                url: this.props.url,
                dataType: 'json',
                catche: false,
                method: 'POST',
                data: {word: this.props.word},
                success: function(data){
                    if(!data.length){
                        this.setState({nodata: true});
                    } else {
                        this.setState({data: data});
                    }
                }.bind(this),
                error: function(xhr, status, error){
                    console.log(this.props.url, status, error.toString());
                    this.setState({error: true});
                }.bind(this)
            });
        }

        render () {
            let body,
                error = this.state.error;

            if(this.state.nodata){
                body = <div>No definition found</div>
            } else {
                body = <DataTab data={this.state.data} title={this.props.word}/>
            }

            return (
                <div className="dictionary-call">
                    {body}
                    {error ? <ServerError onClick={this.callAjax.bind(this)}/> : null}
                </div>
            )
        }
    };

首先根据React docs 使用道具设置初始状态是一种反模式,除非您明确指定它仅用于组件初始化。

从构造函数中可以看出,我将initialLoaded 状态设置为props.load。我将 props.load 作为 true 仅传递给第一个 Accordion 选项卡,因为我希望它最初被加载。

componentDidMount 方法被调用并检查initialLoaded 状态。如果设置为true,它只会调用ajax 并重新渲染组件。

现在是棘手的一点。 componentWillReceiveProps 方法。我期待,当用户单击 Accordion 选项卡将其打开时,该组件将收到nextProps.load。然后将props.load 传递给具有true 值的组件。

我的问题是,componentWillReceiveProps 是打电话给this.callAjax() 的好地方吗?在这种情况下创建initalLoaded 状态似乎有点毫无意义。我不应该简单地基于props.load 并调用shouldComponentUpdate 吗?

或者我应该坚持使用initalLoaded 状态并使用componentWillUpdatecomponentDidUpdate

请记住,当第一次打开手风琴选项卡时,我只想调用一次 ajax 调用。

谢谢!

【问题讨论】:

  • 您是否仅限于使用这种架构?我认为这通过在您的手风琴组件中进行 ajax 调用来延续反模式,这在我看来就像它应该只处理显示数据,而不是获取任何东西。即使在您的顶级组件中,通过更高层处理获取和手风琴状态,这会不会容易得多?
  • 不,我希望每个选项卡从不同的端点获取,另外我想触发基于this.props.open 的获取,所以只有当用户单击选项卡标题时。所以对我来说完全没问题。
  • 我很高兴这对你有用,但我恳请你考虑一种更“反应”的方式来处理这个问题。在 Flux 风格的实现中,您的组件不会进行任何 ajax 调用,所有这些都将在操作层中处理。这使您的组件可以完全专注于事物的外观,很好地解耦行为和状态。
  • 哦,如果是flux/redux,它可能看起来会有所不同。我仅将 React 用作​​ Backbone.js 之上的视图层
  • 但是通过在 UI 组件中进行 ajax 调用,您将视图层逻辑与业务逻辑混合在一起。即使有主干,你也想在顶级组件中做这些事情......我的意思是你可以做到,但是如果你关心以 React 方式做事,并避免反模式......

标签: javascript ajax reactjs lifecycle


【解决方案1】:

所以经过一番研究,我想回答我自己的问题。希望它可以帮助某人。

解决方案非常简单干净(在我看来)。

        componentDidMount () {
            if(this.state.initialLoaded){
                this.callAjax();
            }
        }

        componentWillReceiveProps (nextProps) {
            if(nextProps.load){
                this.setState({initialLoaded: true});
            }
        }

        componentWillUpdate (nextProps, nextState) {
            if(this.state.initialLoaded !== nextState.initialLoaded) {
                this.callAjax();
            }
        }

此代码适用于组件的所有实例,无论它是第一个折叠式选项卡(最初打开)还是其余选项卡(最初关闭)的子级。

componentDidMount 方法中,我正在检查组件是否应该进行Ajax 调用。如果在初始化期间this.props.open 已将this.state.initialLoaded 状态设置为true,则进行ajax 调用。否则当然不会。

现在,当用户单击其他选项卡时,该组件期待 componentWillReceiveProps 中的道具。这里我只在nextProps.load 为真时设置状态,因为我希望仅在load 字段为真时才加载数据。

最后,如果componentWillReceiveProps 中的条件已满足,我将检查this.state.initialLoaded 是否已更改。因为它只有在nextProp.load 为真时才可以更改,它可以防止调用 Ajax 请求的次数过多(当状态从真变为假时)。

这样,我只在第一次打开选项卡时调用 Ajax 请求,或者当它最初打开时。

就这么简单!

【讨论】:

    猜你喜欢
    • 2019-01-02
    • 2017-10-17
    • 1970-01-01
    • 1970-01-01
    • 2018-10-25
    • 2011-07-27
    • 2018-09-09
    • 2018-03-11
    • 2017-09-05
    相关资源
    最近更新 更多