将异步获取的数据传递给 child 道具
Passing asynchronously acquired data to child props
我正在制作一个应用程序,它从远程来源获取一系列新闻项目并将它们显示在页面上。
我有端点,可以使用 $.getJSON()
进行成功调用,控制台日志证明了这一点。我将此调用置于 parent 组件中,因为 child 组件将需要使用数据。
但是,当我将此数据传递给 child 组件时,出现控制台错误:
Uncaught TypeError: Cannot read property 'headline' of undefined
这是因为 React 甚至在数据传入之前就试图渲染组件。这让我觉得我应该首先在 componentDidMount
.
以外的地方调用我的 ajax
为了绕过它,我在 child 组件上设置了一个方法,如果存在道具,returns 标题:
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" 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>
);
}
});
您可以这样做的一种方法是将 this.props.newsItems.headline
设置为 "loading..." 最初以向用户指示数据即将到来。
我建议让父级决定当它处于 "loading" 状态时要做什么,而将 BigStory
作为始终呈现相同内容的 "dumb" 组件假设它将始终收到有效的 newsItem
.
在这个例子中,我展示了一个 <LoadingComponent />
,但这可以是任何你需要的。这个概念是 BigStory
不必担心 "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
组件,但在没有时为其提供 "placeholder story"故事已加载。
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>
);
}
});
这是一个很常见的场景。 John Carpenter 的方法会奏效。我经常使用的另一种方法是创建某种类型的 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>
);
}
我正在制作一个应用程序,它从远程来源获取一系列新闻项目并将它们显示在页面上。
我有端点,可以使用 $.getJSON()
进行成功调用,控制台日志证明了这一点。我将此调用置于 parent 组件中,因为 child 组件将需要使用数据。
但是,当我将此数据传递给 child 组件时,出现控制台错误:
Uncaught TypeError: Cannot read property 'headline' of undefined
这是因为 React 甚至在数据传入之前就试图渲染组件。这让我觉得我应该首先在 componentDidMount
.
为了绕过它,我在 child 组件上设置了一个方法,如果存在道具,returns 标题:
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" 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>
);
}
});
您可以这样做的一种方法是将 this.props.newsItems.headline
设置为 "loading..." 最初以向用户指示数据即将到来。
我建议让父级决定当它处于 "loading" 状态时要做什么,而将 BigStory
作为始终呈现相同内容的 "dumb" 组件假设它将始终收到有效的 newsItem
.
在这个例子中,我展示了一个 <LoadingComponent />
,但这可以是任何你需要的。这个概念是 BigStory
不必担心 "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
组件,但在没有时为其提供 "placeholder story"故事已加载。
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>
);
}
});
这是一个很常见的场景。 John Carpenter 的方法会奏效。我经常使用的另一种方法是创建某种类型的 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>
);
}