How to render array of object in ReactJS - javascript

I want to get list of users using reactJS 15.5, Code:
constructor(props) {
super(props);
this.state = {
values: []
};
this.getDataFromUser = this.getDataFromUser.bind(this);
}
render() {
return (
<div>
<button onClick={this.getDataFromUser}>Fetch</button>
<p>
{this.state.values}
</p>
</div>
);
}
getDataFromUser(){
fetch('http://localhost:8000/api/user')
.then(response => response.json())
.then(json => {
console.log(json);
this.setState({values: json })
})
}
In console.log(json), i get
But i get this error when i click in button Fetch so error in getDataFromUser:
Unhandled Rejection (Invariant Violation): Objects are not valid as a
React child (found: object with keys {id, nom, prenom,
email,is_admin,created_at, updated_at}). 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.
There's a why to create user object, So anyone can help me to resolve this issue and thanks

Its an array of objects so you need to use map to iterate the array then render the specific values.
Like this:
render() {
return (
<div>
<button onClick={this.getDataFromUser}>Fetch</button>
<p>
{this.state.values.map(el => {
return <div key={el.id}>
<span>{el.email}</span>
<span>{el.nom}</span>
<span>{el.is_manager}</span>
</div>
})}
</p>
</div>
);
}

You are trying to return an invalid object/array in your react component. In your case you should try and iterate through the array(this.state.values) and render the items(string values) needed.
render() {
const { values } = this.state;
return (
<div>
<button onClick={this.getDataFromUser}>Fetch</button>
<p>
{values.map((value, index) =>
(<div key={index}>{value.nom}</div>)
)}
</p>
</div>
);
}
Looking at the error it looks like the new state of this.state.values is rather an object with the following keys {id, nom, prenom, email,is_admin,created_at, updated_at}. So the below code would work for u.
render() {
const { values } = this.state;
return (
<div>
<button onClick={this.getDataFromUser}>Fetch</button>
<p>
{values &&
<div>
{values.nom}
{values.prenom}
{values.email}
etc.
</div>
}
</p>
</div>
);
}

Related

TypeError: Cannot read property 'map' of undefined React API

I'm trying to build a products page with list of products with their details fetched from an external API and being displayed as cards. I looked through how to do it and found this to be similar to what I wanted to do but I mimicked the code in this post React fetch api data to component and I'm getting an error TypeError: Cannot read property 'map' of undefined
Products component
class Products extends Component {
constructor(props){
super(props);
this.state = {
items: [],
isLoaded: false,
}
};
componentDidMount = () => {
fetch("https://api.themoviedb.org/3/movie/popular?api_key=xxxxxxxx&page=1")
.then(resp => resp.json())
.then(resp => {
this.setState({
isLoaded: true,
items: resp.results
})
console.log(this.state.items)
})};
render() {
var {isLoaded, items} = this.state;
return (
<div>
{items.map(item => (<Card key={item.id} item={item} />))};
</div>
);
}
}
export default Products;
Card Component
const Card = (props) => {
const { item } = props;
return (
<div className="movie-container">
<img src="https://image.tmdb.org/t/p/w185/{items.poster_path}" alt="NO PHOTO" className="movie-container__img" />
<div className="movie-container__about">
<span className="movie-container__percent">{item.vote_average}</span>
<h2 className="movie-container__title">{item.original_title}</h2>
<p className="movie-container__date">{item.release_date}</p>
<p className="movie-container__text">{item.overview}</p>
MORE
</div>
</div>
)
}
export default Card;
It seems that if render() executes, state.items can be null or undefined, most likely as a result of what your API returns, or how you process what it returns.
The reason to 'blame' the API is because you initialize items to [] in the constructor, so initially there is an array and calling map will work.
To fix this, check if items has a value; if not then don't show anything. And then check if you access the API correctly, perhaps also dive into the API to see what it does and fix it.
It would also be good to check isLoaded so you don't show data unless the API call has finished.
render() {
var {isLoaded, items} = this.state;
if (!isLoaded || !items)
return null; // or if you like, show a "Waiting" indicator
return (
<div>
{items.map(item => (<Card key={item.id} item={item} />))};
</div>
);
}

Array gets undefined in component state (React)

I have an array in a components state that I want to fill with some data from an API call. The problem is that it apparently always gets set do "undefined", and hence I cannot do any functions on it/present the data in the DOM.
This is my code right now:
class DocumentsPage extends Component {
constructor(props) {
super(props);
this.state = { documents: [] };
}
componentDidMount() {
this.getDocuments();
}
getDocuments = (e) => {
fetch('api/GetDocuments').then(documents =>
documents.json()).then(data => {
this.setState({
documents: data
});
})
}
render() {
return (
<div>
{this.state.documents.map(document => <div> {document} </div>)}
</div>
)
}
}
But I get this error when trying to present the data: "TypeError: Cannot read property 'map' of undefined". What am I doing wrong?
EDIT: I changed to this.state.documents.map, but now nothing get presented anyways, no errors either whatsoever. What am I missing?
EDIT #2: Solved it by writing the following code in the render() instead:
return (
<ul>
{this.state.documents.map((document) => (
<li key={document.id}>{document.name}</li>))}
</ul>
)
Write your render like this
render() {
return (
<div>
{this.state.documents && this.state.documents.map(document => <div> {document} </div>)}
</div>
)
}

TypeError: Cannot read property 'map' of undefined - how to access an array in a local json API

I was able to import an api JSON locally using fetch, the api is available in this url if you want to view it.
 
The problem is the following, when passing the state searchString I get the following error:
'TypeError: Can not read property' map 'of undefined'
I believe that is because I am importing the complete json object, whereas I need to access only key results.
File App.js
class App extends Component {
constructor(props) {
super(props);
this.state = {
searchString: []
};
}
componentDidMount() {
fetch('./recipes.json')
.then(response => response.json())
.then(json => console.log(json ))
.then(json => this.setState({ searchString: json }));
}
render() {
return (
<div className="App">
<Navbar />
<div className="container mt-10">
<div className="row">
<RecipeItem list={this.state.searchString}/>
</div>
</div>
</div>
);
}
}
File RecipeItem.js
const RecipeList = ({ searchString }) => {
<div>
<img className="card-img-top img-fluid" src={searchString.href} alt={searchString.title} />
<div className="card-body">
<h5 className="card-title">{searchString.title}</h5>
<p className="card-text">
<strong>Ingredients: </strong>{searchString.ingredients}
</p>
</div>
</div>
}
const RecipeItem = (props) => {
return (
<div className="col-sm-3 mt-4">
<div className="card">
{props.list.map((searchString, index) =>
<RecipeList searchString = {searchString} key={index} />
)}
</div>
</div>
)
}
RecipeItem component doesn't have the data when it's initially mounted, since you're doing a fetch call. So that's why you receive the error.
You can add a simple check if you have data and then do the map/filter/ or anything else:
{props.list && props.list.map((searchString, index) =>
<RecipeList searchString = {searchString} key={index} />
)}
In addition to #chiril's answer, you need to check that the searchString list is actually an array when you set the state (so that the map function will be available):
.then(json => this.setState({ searchString: json })); // check json object is an array

Getting "Object are not valid as a React child" when mapping API response

I have this in App.js:
constructor(props) {
super(props)
this.state = { data: 'false' };
this._getData = this._getData.bind(this);
}
componentDidMount() {
this._getData();
}
_getData = () => {
const url = 'http://localhost:8888/chats';
fetch(url, { credentials: 'include' })
.then((resp) => resp.json())
.then(json => this.setState({ chats: json.chats }))
}
render() {
return (
<div className="App">
{
// console.log(this.props);
this.state.chats &&
this.state.chats.map((item, key) =>
<div key={key}>
{item}
</div>
)
}
<Chat chats={this.state.chats} />
</div>
)
}
And this is the response from http://localhost:8888/chats:
{"chats":[{"buddy":"x","lastMessage":"Hey how are you?","timestamp":"2017-12-01T14:00:00.000Z"},{"buddy":"y","lastMessage":"I agree","timestamp":"2017-12-03T01:10:00.000Z"}]}
Aand I am getting this:
Objects are not valid as a React child (found: object with keys
{buddy, lastMessage, timestamp}). If you meant to render a collection
of children, use an array instead.
in div (at App.js:40) // <div key={key}>
in div (at App.js:35) // <div className="App">
in App (at index.js:6) // ReactDOM.render(<App />,document.getElementById('root'));
and it is poinig at this line
.then(json => this.setState({ chats: json.chats }))
What am I doing wrong ? I read some one saying this
Don't pass an object as a prop to React.child. Instead, pass it as {...item} and then access using props.{property} that might fix your problem
But I'm not sure how to implement!
The problem is when you're mapping:
this.state.chats.map((item, key) =>
<div key={key}>
{item}
</div>
)
If you look at the response from the server, item here is actually an object like this:
{
"buddy": "x",
"lastMessage": "Hey how are you?",
"timestamp": "2017-12-01T14:00:00.000Z"
}
And in React, you can't render an object as a direct child of an element, div in this case. You have to render a specific property of the object:
<div>
{item.lastMessage}
</div>
And if you have multiple things:
<div>
<div>{item.lastMessage}</div>
<div>{item.buddy}</div>
…
</div>
Your json.chats is an array of objects. You are trying to iterate over each one and render them. As the error states, you can't do that. You have to process the object more in order for the elements to render.
json.chats = [{"buddy":"x","lastMessage":"Hey how are you?","timestamp":"2017-12-01T14:00:00.000Z"},{"buddy":"y","lastMessage":"I agree","timestamp":"2017-12-03T01:10:00.000Z"}]
I imagine you are only using buddy and lastMessage. The following would render what you're looking for. Notice that I'm extracting values out of your object and only rendering the values, which are strings.
const chats = json.chats.map(json => {
return (
<div>
{json.buddy}: {json.lastMessage}
</div>
)
})

Update component when prop value changes

I have an object with the property home.ready = false. When the object is done getting data, cleaning it etc it changes to home.ready= true.
I need my component to register the change and update. My component:
class HomeNav extends React.Component {
render() {
let data = this.props.data;
let uniqueTabs = _.uniq(_.map(data, x => x.tab)).sort();
let tabs = uniqueTabs.map((tab, index) => {
let itemsByTab = _.filter(data, (x => x.tab == tab));
return <Tabs key={tab} tab={tab} index={index} data={itemsByTab} />;
});
console.log(this.props)
return (
<section>
<div className="wb-tabs">
<div className="tabpanels">
{ this.props.ready ? {tabs} : <p>Loading...</p> }
</div>
</div>
</section>
)
}
};
ReactDOM.render(
<HomeNav data={home.data.nav} ready={home.ready}/>,
document.getElementById('home-nav')
);
This is the home object. It's a simple object that gets data and once the data is ready the property ready changes from false to true. I can't get React to recognize that change. And at times React will say home is undefined.
Since you didn't post any code around the request, or data formatting, I will assume you got all that figured out. So, for your component to work the way it is currently written, you need to drop the curly braces around tabs ({ this.props.ready ? tabs : <p>Loading...</p> }), then, this.props.data should always contain a valid Array, otherwise it will break when you try to sort, filter, etc.
Or, you can do an early dropout, based on the ready property:
class HomeNav extends React.Component {
render() {
if(!this.props.ready){
return <section>
<div className="wb-tabs">
<div className="tabpanels">
<p>Loading...</p>
</div>
</div>
</section>
}
let data = this.props.data;
let uniqueTabs = _.uniq(_.map(data, x => x.tab)).sort();
let tabs = uniqueTabs.map((tab, index) => {
let itemsByTab = _.filter(data, (x => x.tab == tab));
return <Tabs key={tab} tab={tab} index={index} data={itemsByTab} />;
});
console.log(this.props)
return (
<section>
<div className="wb-tabs">
<div className="tabpanels">
{tabs}
</div>
</div>
</section>
)
}
};

Categories