I am a newbie to react. I have an object. I am trying to get specific value in an object but I am unable to do so. In my case, I am finding the value "Miami, USA" in the description of startLocation. The data object is retrieved from the server through api request and redux action.
1)Uncaught Error: Objects are not valid as a React child (found: object with keys { description, address}). If you meant to render a collection of children, use an array instead.
2)Unhandled Rejection (TypeError): Cannot read property 'description' of undefined
The data I got back from server looks like this,
{
"startLocation": {
"description": "Miami, USA",
"address": "301 Biscayne Blvd, Miami, FL 33132, USA"
},
"name": "Running",
"description": "something", // not this one
}
import React, { Component } from 'react';
import './Page.css';
class Page extends Component {
// some code
render() {
const eventData = this.props.events.data;
const {
name,
startLocation,
description,
} = eventData;
console.log(startLocation["description"]) // undefined
return (
<div className="container">
<div className="heading-group">
<h1 className="header">
<span>{name}</span>
</h1>
<span className="header-text">
{startLocation["description"]}>
</span>
</div>
</div>
)
}
}
const mapStateToProps = (state) => ({
events: state.eventContainer,
});
export default connect(
mapStateToProps,
)(Page);
Any idea?
It works fine with the sample data provided. Perhaps your eventData hasn't imported properly.
const eventOne = {
"startLocation": {
"description": "Miami, USA",
"address": "301 Biscayne Blvd, Miami, FL 33132, USA"
},
"name": "Running",
"description": "something",
}
// destructure object javascript here
const {
name,
startLocation,
description,
} = eventOne;
console.log(description);
console.log(startLocation);
console.log(startLocation["description"]);
Related
I'm making an news app following a tutorial I'm fetching data from newapi my code looks same as tutorial but my component does not change after I update the state (this.state.articles) I'm using setState function i tried console logging the state it looks fine after the state is updated render methods runs but it does not change anything what could be worng
my code/component
import React, { Component } from 'react'
import NewsItem from './NewsItem'
export default class News extends Component {
articles = [
{
"source": {
"id": "espn-cric-info",
"name": "ESPN Cric Info"
},
"author": null,
"title": "PCB hands Umar Akmal three-year ban from all cricket | ESPNcricinfo.com",
"description": "Penalty after the batsman pleaded guilty to not reporting corrupt approaches | ESPNcricinfo.com",
"url": "http://www.espncricinfo.com/story/_/id/29103103/pcb-hands-umar-akmal-three-year-ban-all-cricket",
"urlToImage": "https://a4.espncdn.com/combiner/i?img=%2Fi%2Fcricket%2Fcricinfo%2F1099495_800x450.jpg",
"publishedAt": "2020-04-27T11:41:47Z",
"content": "Umar Akmal's troubled cricket career has hit its biggest roadblock yet, with the PCB handing him a ban from all representative cricket for three years after he pleaded guilty of failing to report det… [+1506 chars]"
},
{
"source": {
"id": "espn-cric-info",
"name": "ESPN Cric Info"
},
"author": null,
"title": "What we learned from watching the 1992 World Cup final in full again | ESPNcricinfo.com",
"description": "Wides, lbw calls, swing - plenty of things were different in white-ball cricket back then | ESPNcricinfo.com",
"url": "http://www.espncricinfo.com/story/_/id/28970907/learned-watching-1992-world-cup-final-full-again",
"urlToImage": "https://a4.espncdn.com/combiner/i?img=%2Fi%2Fcricket%2Fcricinfo%2F1219926_1296x729.jpg",
"publishedAt": "2020-03-30T15:26:05Z",
"content": "Last week, we at ESPNcricinfo did something we have been thinking of doing for eight years now: pretend-live ball-by-ball commentary for a classic cricket match. We knew the result, yes, but we tried… [+6823 chars]"
}
]
constructor() {
super();
this.state = {
articles: this.articles,
loading: false
}
}
async componentDidMount() {
const URL = "https://newsapi.org/v2/top-headlines?country=us&category=business&apiKey="
let data = await fetch(URL);
let parsedData = await data.json()
this.setState({
articles: parsedData.articles
})
console.log(this.state.articles)
}
render() {
console.log("render")
return (
<div>
<div className="container">
<h2 className='my-4 mx-4'> NewsMonkey - Top Headlines </h2>
<div className="row">
{this.articles.map((elem) => {
return <div className="col-md-4" key={elem.url}>
<NewsItem title={elem.title?elem.title.slice(42):""} desc={elem.description?elem.description.slice(0, 88): ""} url={elem.url} imgURL={elem.urlToImage} />
</div>
})}
</div>
</div>
</div>
)
}
}
this.articles and this.state.articles are not the same.
You have a static property this.articles that you are using in the render logic - this.articles.map(.... Your fetch is updating state (like it should be).
Update your render to read from this.state.articles and it should work.
Hi #Curious Your code is correct
you just need to pay attention when making the map
you are using this.articles which is a fixed (mock) list
you need to call map in this.state.articles because this is the state you change in didMount
I created an array of objects with properties of name and birth_date. I then create a Person component and map out the array using props. I'd like to make the name editable so I put the props into an input value. I am trying to use hooks to be able to update that objects name, however, what I currently have only returns an empty value and then edits all values in the table. Any way to specify to only edit that particular objects name and update the array?
NewTable.js
import React, { useState } from 'react';
import './list.css';
import TableHeader from './TableHeader';
import PersonItem from './PersonItem';
import { people } from './people.js';
function NewTable() {
const [itemDetails, editItemDetails] = useState(people.name)
function newPeople(people) {
return (
<PersonItem
name={itemDetails}
date={people.birth_date}
edit={e => editItemDetails(e.target.value)}
/>
);
}
return(
<div id="task-group">
<table className="task-list">
<TableHeader />
<tbody>
{people.map(newPeople)}
</tbody>
</table>
</div>
)
}
export default NewTable;
PersonItem.js
import React from 'react';
import './list.css';
function PersonItem(props) {
return(
<tr>
<td><input type="text" value={props.name} onChange={props.edit}/></td>
<td><input type="text" value={props.date}/></td>
</tr>
)
}
export default PersonItem;
people.js
const people = [
{
name: "John Smith",
birth_date: '01/01/1991',
},
{
name: "Dwayne Johnson",
birth_date: '03/05/1992',
},
]
export { people };
Here is one possible solution:
Have a unique id for every person:
const myPeople = [
{
id: "1",
name: "John Smith",
birth_date: '01/01/1991',
},
{
id: "2",
name: "Dwayne Johnson",
birth_date: '03/05/1992',
},
]
Then pass down this function to the PersonItem component so they can call up and change the state:
const [people, setPeople] = useState(myPeople)
// Pass this function as a prop to PersonItem
function changeNameOfPerson(id, newName) {
const peopleCopy = [...people];
for (let person in peopleCopy) {
if (person.id === id) {
person.name = newName;
}
}
setPeople(peopleCopy);
}
A good practice when using hooks is to name the function that changes the state with the prefix 'set'.
Example: [nameOfYourVar, setNameOfYourVar]
This improves the readability.
Like Mellet said, it's important to use an unique identifier on each object. you can use this id to change an specific object from your array. Source
I got the error: TypeError: Cannot read property 'map' of undefined when I am trying to build a const value to inject inside a Gallery. The const is build using a JSON
Here is the class where the issue happened:
class ClassDetails extends React.Component {
constructor(props, context) {
super(props);
this.state = {anchorEl: null,
showJoin: false,
classDetailsInfo: ''};
}
componentDidMount = () => {
this.setState({classDetailsInfo: ClassDataUseCase.getClassDetails()})
}
render() {
const CLASS_PIC_LIST = this.state.classDetailsInfo.classpic
const GALLERY = CLASS_PIC_LIST.map((pic) => ({
src: pic,
thumbnail: pic, //.replace("1280","_480"), // for example
thumbnailWidth: 156,
thumbnailHeight: 156
}));
...
}
}
export default ClassDetails;
The exact error is TypeError: Cannot read property 'map' of undefined and happened when doing const GALLERY = CLASS_PIC_LIST.map((pic) => ({
The classDetailsInfo is set using ClassDataUseCase.getClassDetails() defined as below:
class ClassDataUseCase {
static getAllClasses() {
return JSON.parse(ClassDetailsData.Classes)
}
static getClassDetails(id) {
var jsonClasses = JSON.parse(ClassDetailsData.Classes);
for(let k=0;k< jsonClasses.length;k++){
if(jsonClasses[k].id===id){
return jsonClasses[k];
}
}
}
}
and the data are coming from the ClassDetailsData which is a JSON as defined below:
class ClassDetailsData {
static Classes = [{
"id": "c000001",
"title": "Cook like a chef",
"price": "5",
"teacher": "Arthur Patrick",
"teacherpic": "https://cdn.pixabay.com/photo/2015/03/03/08/55/portrait-657116_1280.jpg",
"teacherid": "u0000000001",
"desc": "Always want to learn to cook, that's the place you need to be",
"bring": "Your fun , your motivation and you",
"tags": [],
"address": {
"id":"",
"Name": "Joel Robuchon",
"address1": "3799 S Las vegas boulevard",
"address2": "",
"city": "las vegas",
"county": "Clark",
"zip": "89109",
"state": "Nevada",
"country": "United States"
},
"date": "2021/09/01",
"time": "1:00PM",
"duration": "2",
"classpic": ["https://cdn.pixabay.com/photo/2014/06/16/23/10/spice-370114_1280.jpg",
"https://cdn.pixabay.com/photo/2015/08/13/18/47/spices-887348_1280.jpg",
"https://cdn.pixabay.com/photo/2015/04/20/13/30/kitchen-731351_1280.jpg",
"https://cdn.pixabay.com/photo/2015/07/02/10/40/writing-828911_1280.jpg"],
"reviews": [{
"name": "Gabby Caldwell",
"profilePic":"https://cdn.pixabay.com/photo/2015/03/03/08/55/portrait-657116_960_720.jpg",
"rate": "5",
"total_review": "13",
"text": "Rachel was such a kind and knowledgeable guide. She took us to see some hidden coves that a lot of tourists probabaly miss. I’m keeping the map I made FOREVER!!!"
}],
},
{........}
];
}
export default ClassDetailsData;
I do not understand why it's complaining. any idea ? thanks
There might be case when this.state.classDetailsInfo.classpic don't have the value. So initialize it with a default [] if it does not have any value.
You can do it like this:
const CLASS_PIC_LIST = this.state.classDetailsInfo.classpic || [];
In the constructor you are declaring your state with classDetailsInfo as a empty string, and a string doesn't have a .map method on it.
this.state = {anchorEl: null,
showJoin: false,
classDetailsInfo: ''};
You need to declare the classDetailsInfo as an appropriate type for it not to break on the initial render.
this.state = {anchorEl: null,
showJoin: false,
classDetailsInfo: {
classpic: []
}
};
In your state you define classDetailsInfo as a string, that's the reason why you are getting that error
You should set initially it equal to an empty array [] to avoid unexpected behavior
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
classList: ''
}
}
componentDidMount() {
this.setState({classList: ["name", "data", "test"]});
}
render() {
return <div>
{this.state.classList.map(cl => <span>{cl}</span>)}
</div>
}
}
ReactDOM.render(<App/>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.1.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.1.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>
You can look this simple example, If I change the value of state key classList to an [] every thing work as expected. But now It reproduces the same error you get
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
classList: []
}
}
componentDidMount() {
this.setState({classList: ["name", "data", "test"]});
}
render() {
return <div>
{this.state.classList.map(cl => <span>{cl}</span>)}
</div>
}
}
ReactDOM.render(<App/>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
In the second example after I initialize classList to an array it work.
I am trying to access single elements within an object and I keep getting an error.
Here is my React Component:
import React, { Component } from "react";
import { fetchCoin } from "../redux/actions";
import { connect } from "react-redux";
class ViewCoin extends Component {
componentDidMount() {
this.props.fetchCoin(this.props.match.params.symbol);
}
render() {
console.log("Props:", this.props.coin);
return (
<div>
<h2>View Item Page</h2>
</div>
);
}
}
const mapStateToProps = state => {
return {
coin: state.coins.coin
};
};
export default connect(mapStateToProps, { fetchCoin })(ViewCoin);
This code returns the following object:
{
"BTC": {
"urls": {
"website": [
"https://bitcoin.org/"
],
"twitter": [],
"reddit": [
"https://reddit.com/r/bitcoin"
],
"message_board": [
"https://bitcointalk.org"
],
"announcement": [],
"chat": [],
"explorer": [
"https://blockchain.info/",
"https://live.blockcypher.com/btc/",
"https://blockchair.com/bitcoin/blocks"
],
"source_code": [
"https://github.com/bitcoin/"
]
},
"logo": "https://s2.coinmarketcap.com/static/img/coins/64x64/1.png",
"id": 1,
"name": "Bitcoin",
"symbol": "BTC",
"slug": "bitcoin",
"date_added": "2013-04-28T00:00:00.000Z",
"tags": [
"mineable"
],
"category": "coin"
}
}
When trying to access the coin name, for example, I issue the command:
console.log(this.props.coin.BTC.name);
I get the error: Cannot read property 'BTC' of undefined
I tested accessing values in this object outside of React and I am able to access the different values. How would one access a nested object like this using React.
Thanks in advance.
What's likely happening is the first time that component renders coin is undefined. When the action returns, the props are updated, the component re-renders and coin is logged out.
Do something like this in render and it should work:
this.props.coin && console.log('coin name:', this.props.coin.BTC.name)
I have tried many tutorials and so far, I can display items and get a little bit around React.
The URL structure is
/works/2
The query string of 2 is stored inside of pageID
I then fire the ajax call and filter the database to only show that data with .find()
This is the WorksPage.js file which will list the company work portfolio items.
import React, { Component } from 'react';
import axios from 'axios';
import './index.css';
class WorksPage extends Component {
constructor(props) {
super(props);
this.state = {itemList: []};
}
componentWillMount(){
const pageID = this.props.match.params.page;
axios.get('/api/works.json').then(function(response){
const result = response.data.find(i => i.id === pageID);
this.setState({ isLoaded: true, itemList: result });
}.bind(this));
}
componentDidMount() {
window.scrollTo(0, 0);
}
render(){
return(
<div className="workListing pageWrapper">
<section className="workListing-process">
<div className="smcontainer center txtc">
{this.state.itemList}
App Type: {this.state.itemList.sub}
App cars: {this.state.itemList.cars.map((car, i) =>
<div key={i}>
{car}
</div>
)}
</div>
</section>
</div>
)
}
}
export default WorksPage;
My JSON of works.json is
[{
"id": 0,
"img": "/images/slider.jpg",
"header": "GPS Module",
"sub": "iOS",
"link": "/works/0",
"cars":[ "Ford", "BMW", "Fiat" ]
}{
"id": 1,
"img": "/images/map-slider.jpg",
"header": "GPS Mapping Vectors",
"sub": "iOS",
"link": "/works/1",
"cars":[ ]
},{
"id": 2,
"img": "/images/slider.jpg",
"header": "GPS Module",
"sub": "Android",
"link": "/works/2",
"cars":[ "Ferrari", "BMW", "Land Rover" ]
}]
So far the {this.state.itemList} returns blank. The car list loop is also not working. Console.log will return the data of result if I do the console.log after the this.setState
First of all, do not use componentWillMount, it's both deprecated and not meant for calling APIs. Use componentDidMount instead.
I assume the problem is that pageID is string and id is number, thus nothing gets matched. Try converting pageID to number before comparing it.
const pageID = parseInt(this.props.match.params.page, 10);
You use 'this' keyword in callback function, and it refers to the call back itself not the component.
and also use componentDidmount, componenwillmount is not used anymore.
see here : componentWillMount
use this :
componentDidMount(){
let that = this;
const pageID = this.props.match.params.page;
axios.get('/api/works.json').then(function(response){
const result = response.data.find(i => i.id === pageID);
that.setState({ isLoaded: true, itemList: result });
};
}