将异步获取的数据传递给子道具

Posted

技术标签:

【中文标题】将异步获取的数据传递给子道具【英文标题】:Passing asynchronously acquired data to child props 【发布时间】:2016-03-29 03:57:25 【问题描述】:

我正在制作一个应用程序,它从远程源获取一系列新闻项目并将它们显示在页面上。

我有端点,并且可以使用$.getJSON() 进行成功的调用,控制台日志证明了这一点。我将此调用放入父组件中,因为子组件将需要使用数据。

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

Uncaught TypeError: Cannot read property 'headline' of undefined

这是因为 React 甚至在数据传入组件之前就尝试渲染组件。这让我觉得我应该首先在 componentDidMount 以外的地方调用我的 ajax。

为了解决这个问题,我在子组件上设置了一个方法,如果 prop 存在则返回标题:

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

这感觉有点令人讨厌。有没有更好的方法,还是我的代码中遗漏了什么?

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" />
                </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>
        );
    
);

【问题讨论】:

【参考方案1】:

我建议将它留给父级来决定当它处于“加载”状态时要做什么,并将 BigStory 作为一个“哑”组件,假设它总是会收到一个有效的 @ 987654322@.

在这个例子中,我展示了一个&lt;LoadingComponent /&gt;,但这可能是你需要的任何东西。这个概念是BigStory 不必担心“接收无效数据”的边缘情况。

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 组件,但在没有加载故事时为其提供“占位符故事”。

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>
    );
  
);

【讨论】:

这是一个非常有帮助的答案,非常感谢。很高兴看到你也可以使用 ES6。【参考方案2】:

这是一个很常见的场景。约翰卡彭特的方法会奏效。我经常使用的另一种方法是创建某种类型的带有微调器图像的Loading 组件(或者您可能用来表示数据正在传输的任何其他方法)。然后,在客户端等待数据到达时,您可以渲染该Loading 组件。例如:

render: function () 
    if (this.state.newsItems.length === 0) return <Loading />;
    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>
    );

【讨论】:

【参考方案3】:

您可以这样做的一种方法是将this.props.newsItems.headline 设置为“正在加载...”,以向用户指示数据即将到来。

【讨论】:

以上是关于将异步获取的数据传递给子道具的主要内容,如果未能解决你的问题,请参考以下文章

Vue父组件道具没有传递给子组件

Vue JS rc-1 通过道具传递数据不起作用

如何将数据传递给嵌套的子组件vue js?

在Vuetify和Vue JS中将道具传递给父母

Vue2将任意命名变量作为道具传递

微信小程序如何将接口获取的数据传递给自定义组件