Accessing State that holds Array of Objects - reactjs

I apologize if this is a basic question, but I'm genuinely confused why this isn't working. I have a component that makes an API call to fetch data, and the data returns successfully, and I can do a console.log and see an array of objects as I expect.
.then((result) => {
this.setState({
surveyData: result,
surveyYear: result[0].year
});
console.log(result); <--- This logs an array of objects as expected
console.log(this.state.surveyData); <-- This logs an empty array
console.log(this.state.surveyYear); <-- This logs what I expect
})
When I use the return component, I get what I expect from this:
render(){
return(
<p>{this.state.surveyYear}</p> <--- this shows exactly what I'd expect
)
}
But if I do the below, it should show the exact same data, but instead, I get this error: TypeError: Cannot read properties of undefined (reading '0') Is it possible to do this way?
render(){
return(
<p>{this.state.surveyData[0].year</p> <--- I want to access the data this way instead
)
}

This is a common pitfall in react. The issue is that updating the state is not instantaneous. This is why your data is not there yet right after the call to setState. Similarly in the render method you will need to guard against that data not being available yet.
If you babel your code and support the optional chaining operator:
render(){
return(<p>{this.state.surveyData?.[0]?.year</p>)
}
otherwise
render(){
return(<p>{this.state.surveyData && this.state.surveyData[0] && this.state.surveyData[0].year</p>)
}

Related

Components not rendered when receiving arrays from parents

data.Example.map((item) => {
console.log(item.A)
return <ExampleBlock
a={item.A}
b={item.B}
/>
})
The data object in this code is imported from local json object. Here, console.log(item.A) just helps me to check if this is really an array.
postList.forEach(post => {
post.data.Example.map((item) => {
console.log(item.A)
return <ExampleBlock
a={item.A}
b={item.B}
/>
})
})
The postList here is imported from firestore. I exercise cautious here with console.log(item.A) and have verified that it's indeed an array like I drawn from local json file in the previous code set.
Both console.log shows the same thing.
Weird thing here is. The first set of code works just fine. It passed down the arrays as props and component is rendered perfect. The second set of code, the component wasn't rendered and it's just blank.
I've tried hard to think what's wrong and what's the difference. Would you guys please point me to the right direction. THanks.
It's due to the forEach which returns nothing. Replace it with a map as follows:
postList
.map((post) => post.data.Example)
.map((item) => {
console.log(item.A);
return <ExampleBlock a={item.A} b={item.B} />;
})

React can not access variable from return

I am very new to React and I can not solve this issue for a very long time. The idea is the following, I get some user info from database and pass it into cookies. From react side I get this cookies as JSON object and I need to render menu for user depending on values in this object. Right now I pass this object that I get from cookies from parent Component and I try to access it from Settings component. The issue is that I can see access this object from test function, however when I try to access this data from return it gives me undefined error. The function that returns value from cookies is sync, I have no idea why that might happen, please help.....
Since this.state.shopSettings["new_orders"] is boolean, use ternary.
Don't copy props to the state inside constructor as the constructor is executed only once. So updates to the props won't be reflected in the component.
Like this
<button onClick={this.test}>
{props.shopSettings && (props.shopSettings["new_orders"] ? 'true button' : 'false button')}
</button>
It solves very easily with this code, now I can access any key from shopSettings inside return without any issues
class Index extends React.Component {
state = {
shopSettings: Cookies.getJSON('shopSettings')
}
render() {
const {shopSettings} = this.state
if (!shopSettings) {
return null
}
return (
<div>Hello</div>
)
}

Updating the state of an array on React

I am having problems with the response data I get from an API. I use axios to get the JSON object, and the state should be replaced by the list of objects every time the API is called.
Here is the code.
https://i.stack.imgur.com/yHXn0.png
And here is the console
https://i.stack.imgur.com/KnHD2.png
I imagine I am updating the state wrong, but I cant see what it is.
Your error message is pretty clear.
Cannot read property 'push' of undefined
What does that mean? it means you called the method push on a variable that is still undefined
let paineis = empresas.map( (empresa, i) => {
paineis.push(<Painel key={i} nome={empresa.nome} usuarios={empresa.usuarios} />)
// ^-----^
// this is the issue. paineis has not yet been assigned a value!
})
The real issue here is you are using map incorrectly. the return value in a map is the way to push a new value. You want to do this instead
let paineis = empresas.map( (empresa, i) => <Painel key={i} nome={empresa.nome} usuarios={empresa.usuarios} />)
this is an ES6 shorthand for a return, also could be written
let paineis = empresas.map( (empresa, i) => {
return <Painel key={i} nome={empresa.nome} usuarios={empresa.usuarios} />
})

Cannot read property 'destination' of undefined when react state is an array

when my react state is an object, I can get its property in render method,
but when I set the state to array and use state[0].property in render method, it give me the undefined error, cannot figure out, any help??? Thanks!!!
class App extends Component {
state={
dataArray:[]
}
componentDidMount(){
this.getTrainInfo();
}
getTrainInfo=()=>{
fetch('https://api-v3.mbta.com/routes')
.then(response=>response.json())
.then(res=>{
//res will return an array of objects
let arr=[];
let data={};
data.destination=res.data[0].attributes.direction_destinations[0];
data.lineID=res.data[0].relationships.line.data.id
arr.push(data);
this.setState({dataArray:arr});
//I put a console.log(dataArray) here, I can get
// [{destination:xxx, lineID:xxx }] back.
})
}
render() {
//in here, I also can get the array: [{destination: xxx, lineID: xxx}]
let data=this.state.dataArray;
//but in here, I get error saying property destination is undefined,
//why?
let destination=data[0].destination;
//console.log(destination);
return (
<div className="App">
<h1>Train info</h1>
</div>
);
}
}
This is normal behavior. React will render you component a single time before ever executing the logic in componentDidMount() Which is why you're getting the undefined error because your inital state starts out as an empty array.
To resolve this, it is common practice to have a "loading state" while your component updates with the new data. So when the state is finally updated, your component will re-render and display your desired content.
In your render, try doing something like:
render() {
let data=this.state.dataArray;
if(this.state.dataArray.length == 0){
return Loading...
} else {
return (
<div className="App">
// whatever logic you want to display
<h1>Train info</h1>
</div>
)
}
You need to add condition because on initial render the dataArray is empty array and doesn’t have any objects in it.
From second render on wards you have data in dataArray so add below condition
if(this.state.dataArray.length){ //this condition will be true when dataArray length is greater than zero
let destination=data[0].destination;
console.log(destination); //this will print the value
}

If/Guard Clauses in React/Redux Components

I have a React component that is being rendered and some initial data isn't available just yet. Because of that, I have these two if blocks (guard clauses) that check to see if we're in a state to even bother rendering. Basically, when this component is used, we're in a state where we have header records for the data, but none of the detail records yet. So this component is recognizing that and retrieving the detail before displaying.
This feels wrong, like this isn't the way it should be done in React/Redux. Further, that second if block could possibly cause an infinite loop. It basically checks to see if we have detail data for a header record. If not, we return and call props.onSortItemChanged() to begin the process of fetching the data. What if the data doesn't exist? Then we'd come back here and make the call again. Anyway, that's just one issue.
The main issue is that I believe a component like this shouldn't know or care about having to fix/retrieve data. It should just display with data that's already in a correct form. Is that right? If so, where is the right place to check and make sure the data is in good form? The action? The reducer?
render() {
const {
printSortOptions,
printSortDetails,
selectedPrintSortOption,
printSortDrawerEvent
} = this.props;
if (printSortDrawerEvent === printSortDrawerEventTypes.CLOSE ||
printSortDrawerEvent === printSortDrawerEventTypes.FAIL) {
return <div id="emptyDiv" />;
}
if (printSortOptions && printSortDetails.length === 0) {
const selectedOptions = printSortOptions.filter(o => o.isDefault);
this.props.onSortItemChanged(selectedOptions[0]);
return this.constructor.loadingJsx();
}
const selectedPrintSortDetails = printSortDetails.filter(
d => d.printSortOption.printSortId === selectedPrintSortOption.printSortId)[0];
return (
<div className="col-xs-12">
// remaining JSX here
)
}

Resources