将异步获取的数据传递给子道具 [英] Passing asynchronously acquired data to child props

查看:59
本文介绍了将异步获取的数据传递给子道具的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个应用程序,该应用程序可以从远程来源获取一系列新闻,并将其显示在页面上.

I am making an app that gets an array of news items from a remote source and displays them on a page.

我有终结点,可以使用 $.getJSON()进行成功的呼叫,控制台控制台证明.我将此调用放入了父组件中,因为子组件将需要使用数据.

I have the endpoint, and can make a successful call, proven by console logs, using $.getJSON(). I placed this call into the parent component, because child components will need to use the data.

但是,当我将此数据传递给子组件时,出现控制台错误:

However, when I pass this data down to a child component, the console error appears:

未捕获的TypeError:无法读取未定义的属性"headline"

这是因为React甚至在将数据传递到组件之前就尝试渲染该组件.这使我认为我应该首先在 componentDidMount 之外的其他地方调用我的Ajax.

This is because React is trying to render the component even before the data has been passed into it. This makes me think I should first be calling my ajax somewhere other than componentDidMount.

要解决此问题,我在子组件上设置了一个方法,如果该道具存在,则该方法返回标题:

To get around it, I set up a method on the child component that returns the headline if the prop is present:

getHeadline: function () {
    if(this.props.newsItems){
        return this.props.newsItems.headline
    } else {
        return null
    }
},

感觉好像有点讨厌.有没有更好的方法,还是我的代码中缺少某些内容?

This feels like a bit of a nasty way around it. Is there a better way, or am I missing something in my code?

var BigStory = React.createClass({

    getHeadline: function () {
        if(this.props.newsItems){
            return this.props.newsItems.headline
        } else {
            return null
        }
    },

    render: function () {
        console.log('props:', this.props);
        console.log('newsItems:', this.props.newsItems);
        return (
            <div className="big-story col-xs-12">
                <div className="col-sm-5">
                    <h1>{this.getHeadline()}</h1>
                    <p>Placeholder text here for now.</p>
                    <p>time | link</p>
                </div>
                <div className="col-sm-7">
                    <img src="http://placehold.it/320x220" alt=""/>
                </div>
            </div>
        );
    }
});

var Main = React.createClass({

    getInitialState: function () {
        return {
            newsItems: []
        }
    },

    componentDidMount: function () {
        this.getNewsItems();
    },

    getNewsItems: function () {
        $.getJSON('http://www.freecodecamp.com/news/hot', (data) => {
            console.log('data sample:', data[0]);
            this.setState({newsItems: data})
        })
    },

    render: function () {
        return (
            <div className="container">
                <div className="main-content col-sm-12">
                    <div className="left-sided-lg-top-otherwise col-lg-8 col-md-12 col-sm-12 col-xs-12">
                        <BigStory newsItems={this.state.newsItems[0]}/>
                    </div>
                </div>
            </div>
        );
    }
});

推荐答案

我建议让它交给父母来决定当它处于加载"状态并离开 BigStory 时该怎么做.作为一个哑"组件,假定始终将收到有效的 newsItem .

I would suggest leaving it up to the parent to decide what to do when it is in a "loading" state and leaving BigStory as a "dumb" component that always renders the same assuming it will always receive a valid newsItem.

在此示例中,我显示< LoadingComponent/> ,但这可以是您需要的任何内容.概念是 BigStory 不必担心接收无效数据"的极端情况.

In this example, I show a <LoadingComponent />, but this could be whatever you need it to be. The concept is that BigStory shouldn't have to worry about edge cases with "receiving invalid data".

var Main = React.createClass({
  // ...
  render() {
    const {newsItems} = this.state;
    // You could do this, pass down `loading` explicitly, or maintain in state
    const loading = newsItems.length === 0;
    return (
      <div className="container">
          <div className="main-content col-sm-12">
              <div className="left-sided-lg-top-otherwise col-lg-8 col-md-12 col-sm-12 col-xs-12">
                  {loading 
                    ? <LoadingComponent />
                    : <BigStory newsItem={newsItems[0]} />  
                  }
              </div>
          </div>
      </div>
    );
  }
});

function BigStory(props) {
  // Render as usual. This will only be used/rendered w/ a valid
  return (
    <div className="big-story col-xs-12">
      <h1>{props.headline}</h1>
      {/* ... */}
    </div>
  )
}

另一种解决方案(尽管我建议使用类似上述的方法)将始终以相同的方式使用 BigStory 组件,但在没有该组件的情况下为其提供占位符故事"故事已加载.

An alternative solution (although I recommend an approach more like above) would be to always make use of the BigStory component in the same way, but provide it a "placeholder story" when there are no stories loaded.

const placeholderNewsItem = {
  headline: 'Loading...',
  /* ... */
};

var Main = React.createClass({
  // ...
  render() {
    const {newsItems} = this.state;
    // Conditionally pass BigStory a "placeholder" news item (i.e. with headline = 'Loading...')
    const newsItem = newsItems.length === 0
      ? placeholderNewsItem
      : newsItems[0];
    return (
      <div className="container">
          <div className="main-content col-sm-12">
              <div className="left-sided-lg-top-otherwise col-lg-8 col-md-12 col-sm-12 col-xs-12">
                  <BigStory newsItem={newsItem} />
              </div>
          </div>
      </div>
    );
  }
});

这篇关于将异步获取的数据传递给子道具的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆