I have the following component that is a lot like the React.js main tutorial. Basically, I have an api that I'm pulling from and trying to load the data:
var Box = React.createClass({
getInitialState: function () {
return {
data: {
items: []
}
};
},
loadStuffFromServer: function() {
$.ajax({
url: this.props.url,
dataType: 'json',
cache: false,
success: function(data) {
this.setState({data: data});
}.bind(this),
error: function(xhr, status, err) {
console.error(this.props.url, status, err.toString());
}.bind(this)
});
},
componentDidMount: function() {
this.loadStuffFromServer();
},
render: function() {
var blah = this.state.data;
return (
<div>
{ blah }
</div>
);
}
});
However when I put blah there, I get the error: Uncaught Error: Invariant Violation: Objects are not valid as a React child (found: object with keys {items}). If you meant to render a collection of children, use an array instead or wrap the object using createFragment(object) from the React add-ons. Check the render method ofBox.
I call my component with react rails and <%= react_component('Box',url: "URLHERE", pollInterval: 1000) %>
Use Array (data.items) instead of Object
var blah = this.state.data.items;
__________________________^^^^^^___
render: function () {
var blah = this.state.data.items.map(function (item) {
return <p>
{ item.content }
</p>;
});
return <div>
{ blah }
</div>;
}
Adding to what Alexander said, you don't have to assign state's value to a variable. You can directly do- inside the div tag
<div> { this.state.data.items } <div>
And Use a .map to get the values.
{this.state.data.items.map(objval =>
<div>
{objval.name}
</div>
)}
Hope it helps :)
Related
UPD: How can I display elment of the array in my component (WeatherCityName - h2)? It can be seen that the array is loaded, but when I point out the property - an error occurs, it may be a problem in the syntax?
var WeatherBox = React.createClass({
handleWeatherSubmit: function(text) {
$.ajax({
url: this.props.url,
dataType: 'json',
type: 'POST',
data: 'cityName=' + text,
success: function(data) {
this.setState({data: data});
}.bind(this),
error: function(xhr, status, err) {
console.error(this.props.url, status, err.toString());
}.bind(this)
});
},
getInitialState: function() {
return {data: []};
},
render: function() {
return (
<div className="wetherBox">
<h1> Weather</h1>
<WeatherForm onWeatherSubmit={this.handleWeatherSubmit} />
<WeatherCityName data={this.state.data[0]} />
<WeatherList data={this.state.data} />
</div>
);
}
});
var WeatherCityName = React.createClass({
render: function(){
return(
<h2>{this.state.data[0].cityName}</h2>
);
}
});
Sure, just put <h2>{weatherItem.cityName}</h2> directly in the <div>.
var WeatherList = React.createClass({
render: function() {
var weatherNodes = this.props.data.map(function(weatherItem) {
return (
<div className="city-item-with-title">
<h2>{weatherItem.cityName}</h2>
<WeatherItem
cityid={weatherItem.cityid}
type={weatherItem.type}
src={weatherItem.src}
temp={weatherItem.temp}
tempFrom={weatherItem.tempFrom}
tempTo={weatherItem.tempTo}
key={weatherItem.id}
/>
</div>
);
});
return (
<div className="weatherList">
{weatherNodes}
</div>
);
}
});
Edit: I'm not sure which weather item you want to use as a title, perhaps this.props.data[0]?
Edit 2: Just assumed you want to use the first weather item.
Edit 3: One title for each weatherItem, grouped inside a div together with the corresponding weatherItem.
I have the following ReactJS code:
var CommentList = React.createClass({
render: function(){
var commentNodes = this.props.data.map(function(comment){
return (
<Comment author={comment.author} key={comment.id}>
{comment.text}
</Comment>
);
});
return (
<div className="commentList">
{commentNodes}
</div>
);
}
});
And in CommentBox....
var CommentBox = React.createClass({
loadCommentFromServer: function() {
$.ajax({
url: this.props.url,
dataType: 'json',
cache: false,
success: function(data) {
this.setState({
data: data
});
}.bind(this),
error: function(xhr, status, err) {
console.error(this.props.url, status, err.toString());
}.bind(this)
});
},
},
getInitialState: function() {
return {
data: []
};
},
componentDidMount: function() {
this.loadCommentFromServer();
setInterval(this.loadCommentFromServer, this.props.pollInterval);
},
render: function() {
return (
<div className = "commentBox" >
<h1> Comments </h1>
<CommentList data ={ this.state.data } />
<CommentForm />
</div>
);
}
});
In getInitialState(), I already assign value for data and in CommentList also add property data which get value from state.
When I try to run, I got this error:
Cannot read property 'map' of undefined in CommentList.
It looks like you simply aren't getting the data you want back from the jQuery.ajax.
success: function(data) {
// before setting state, log here and find out what data is
// it could need to be turned into JSON? data = data.toJSON();
// or simply this to be safe
data = data || [];
this.setState({
data: data
});
}
i have an app which loads data from mongodb to list component like this
React.render(<ProductsList url="http://localhost:3000/data"/>, document.getElementById('products'));
and then i try make a http get call to ge the data like this
var ProductsList = React.createClass({
loadData: function() {
$.ajax({
url: this.props.url,
dataType: 'json',
success: function(data) {
<ProductsList url={data}/>
},
error: function(xhr, status, err) {
console.error(this.props.url, status, err.toString());
}
});
},
render: function() {
this.loadData();
var products = this.props.url.map(function(product) {
return (
<li key={product._id}>
<Product data={product} />
</li>
)
});
return (
<ul className="clearfix">
{products}
</ul>
);
}
});
but when i load the app i get this error Uncaught TypeError: this.props.url.map is not a function what could the problem be ?
map is not a function for strings, check the documentation for array map: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
Furthermore, not related to your error, but your function loadData returns undefined, because you are just making the ajax call. In order to make this work, you need to use the state object of the react component call this.setState() in your success/error hooks.
it's seems like you are not clear about the props and state of React you have to follow in below mentioned way
var ProductsList =React.createClass({
getInitialState:function()
{
return{
url:[]
}
},
componentDidMount:function()
{
var that=this;
$.ajax({
url: 'https://api.github.com/users/mralexgray/repos',
dataType: 'json',
success: function(data) {
that.setState({url:data});
},
error: function(xhr, status, err) {
console.error(this.props.url, status, err.toString());
}
});
},
ChangeContent:function()
{
this.setState({content:"change Content"});
},
render:function()
{
var Products = this.state.url.map(function(product) {
return (
<li key={product._id}>
{product.full_name}
</li>
)
});
return(
<div>
{Products}
</div>
)
}
});
React.render(
<ProductsList />,
document.getElementById('example')
);
Demo
I'm having a hard time understanding why I can't do something like this.
loadPostsFromServer: function() {
$.ajax({
url: '/allPosts',
dataType: 'json',
success: function(data) {
console.log(data);
this.setState({posts:data, items:data});
//this.setState({items:data});
}.bind(this),
error: function(xhr, status, err) {
console.error(this.props.url,status, err.toString());
}.bind(this)
});
},
loadUserFromServer: function() {
$.ajax({
url: '/user',
dataType: 'json',
success: function(data) {
this.setState({user:data.local});
//console.log(this.state.user);
}.bind(this),
error: function(xhr, status, err) {
console.error(this.props.url,status, err.toString());
}.bind(this)
});
},
getInitialState: function() {
return {
posts: [],
items: [],
user: []
}
},
componentDidMount: function() {
this.loadPostsFromServer();
this.loadUserFromServer();
//this.setState({items: this.state.posts});
//setInterval(this.loadPostsFromServer, this.props.pollInterval);
},
render: function() {
<div className="Posts">
<List user={this.state.user} posts={this.state.items} />
</div>
}
Where List can be something like this and can't do the this.props.user print
var List = React.createClass({ //has to be called list
render: function() {
return (
<p>{this.props.user}</p>
<ul>
{
this.props.posts.map(post){
return (<p>{post.title}</p>)
})
}
</ul>
)
}
});
but can do this:
var List = React.createClass({
render: function() {
return (<p>{this.props.user}</p>)
}
});
Basically I'm passing two props in my real function, and the ajax call is delivering down a array user, with user info, and array post with post info. I can display the post info fine, and the user info is complete as well, however I cannot actually display the user info received from the ajax get call. I printed out the state of the array as well and it was complete and filled. However passed down it would return messages like cannot read {this.props.user.firstName} and such, however writing it the second way and not including posts, it works fine. How can I use both props in a map function?
Be careful, in render function, you always need a wrap tag to make React work. You should add <div> tag to the render of List component.
var List = React.createClass({ //has to be called list
render: function() {
return (
<div> <-- ALWAYS HAS A WRAP TAG
<p>{this.props.user}</p>
<ul>
{
this.props.posts.map(post){
return (<p>{post.title}</p>)
})
}
</ul>
</div>
)
}
});
This code below works because there is <p> to wrap contents.
var List = React.createClass({
render: function() {
return (<p> <-- WRAP TAG
{this.props.user}
</p>)
}
});
I have implemented a little test application in React to fetch data via AJAX, but it is not working as inteded, hence i get following error:
Uncaught TypeError: Cannot read property 'map' of undefinedInline JSX script
Code is as following:
<div id="content"></div>
<script type="text/jsx">
var Bodypart = React.createClass({
render: function() {
return (
<div>
{this.props.name}
</div>
)
}
})
var BodypartList = React.createClass({
getInitialState: function() {
return {data: []};
},
componentWillMount: function() {
$.ajax({
url: this.props.url,
dataType: 'json',
success: function(data) {
this.setState({bodyparts: data});
}.bind(this),
error: function(xhr, status, err) {
console.error(this.props.url, status, err.toString());
}.bind(this)
});
},
render: function() {
var bodypartItems = this.state.bodyparts.map(function (bodypart) {
return (
<Bodypart
name={bodypart.name}
/>
);
});
return (
<div>
{bodypartItems}
</div>
);
}
});
React.render(
<BodypartList url="/api/bodyparts/" />,
document.getElementById('content')
);
</script>
The response from /api/bodyparts/:
{
"bodyparts": [
{
"id": 1,
"name": "Face"
},
{
"id": 3,
"name": "Mouth"
},
{
"id": 2,
"name": "Nose"
}
]
}
At initial render this.state.bodypartsis undefined hence the error you got.
you should return
{bodyparts:[]}
from getInitialState.
Also in your success callback you should set state like:
this.setState(data);
because your api already returns bodyparts as part of its result.
this.state.bodyparts is undefined. the component is rendering before the ajax has completed. Try setting an initial state