admin管理员组文章数量:1306951
I am making an app that gets an array of news items from a remote source and displays them on a page.
I have the endpoint, and can make a successful call, proven by console logs, using $.getJSON()
. I placed this call into the parent ponent, because child ponents will need to use the data.
However, when I pass this data down to a child ponent, the console error appears:
Uncaught TypeError: Cannot read property 'headline' of undefined
This is because React is trying to render the ponent even before the data has been passed into it. This makes me think I should first be calling my ajax somewhere other than ponentDidMount
.
To get around it, I set up a method on the child ponent 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="" alt=""/>
</div>
</div>
);
}
});
var Main = React.createClass({
getInitialState: function () {
return {
newsItems: []
}
},
ponentDidMount: function () {
this.getNewsItems();
},
getNewsItems: function () {
$.getJSON('', (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>
);
}
});
I am making an app that gets an array of news items from a remote source and displays them on a page.
I have the endpoint, and can make a successful call, proven by console logs, using $.getJSON()
. I placed this call into the parent ponent, because child ponents will need to use the data.
However, when I pass this data down to a child ponent, the console error appears:
Uncaught TypeError: Cannot read property 'headline' of undefined
This is because React is trying to render the ponent even before the data has been passed into it. This makes me think I should first be calling my ajax somewhere other than ponentDidMount
.
To get around it, I set up a method on the child ponent 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: []
}
},
ponentDidMount: function () {
this.getNewsItems();
},
getNewsItems: function () {
$.getJSON('http://www.freecodecamp./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>
);
}
});
Share
Improve this question
asked Dec 22, 2015 at 19:49
alanbuchananalanbuchanan
4,1738 gold badges43 silver badges66 bronze badges
3 Answers
Reset to default 4I 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" ponent that always renders the same assuming it will always receive a valid newsItem
.
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>
)
}
An alternative solution (although I remend an approach more like above) would be to always make use of the BigStory
ponent 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>
);
}
});
This is a pretty mon scenario. John Carpenter's approach would work. Another approach that I use often would be to create some type of Loading
ponent with a spinner image (or whatever else you might use to signify that data is on its way). Then, while the client waits for the data to arrive, you can render that Loading
ponent. For example:
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>
);
}
One way you could do it is to set this.props.newsItems.headline
to "loading..." initially to indicate to the user that data will be ing.
本文标签: javascriptPassing asynchronously acquired data to child propsStack Overflow
版权声明:本文标题:javascript - Passing asynchronously acquired data to child props - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741825128a2399597.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论