Reputation: 464
I'll preface this by saying it's only my second day working with react and I'm no expert in coding either. I would appreciate any answers to this to be explained as such. Any and all responses are however greatly valued.
I am trying to understand the relationship between the state and render(). I have defined a data object called myDataObj
. The App component grabs some variables in the constructor. I create a variable called someData
which takes a dataobject and myVar
which is an integer. The render function is executed the first time. Each of my console.logs are logged to the console. The componentDidMount function is then executed after the render, then the render is ran again due to the setState method.
My question is why can I not get the two lines that I have commented out to pull the value from the state? I am able to directly access those variable (within scope) by referencing them directly: myDataObj.myData[0]
. I can access the myVar
variable via the state as shown in this.state.myVar
.
When trying to push a new item into myDataObj via someData.myData.push({name:'Item 4'});
I get a 'someData' is not defined.
When trying to log the first element of the variable via {console.log(this.state.someData.myData[0])}
I get a 'Cannot read propert '0' of undefined.
Hopefully I was able to articulate the problem correctly. The code is below.
Thank you
import React, {Component} from 'react';
import './App.css';
let myDataObj = {
myData: [
{name:'Item 1'},
{name:'Item 2'},
{name:'Item 3'}
]
};
let myVar = 2
class App extends Component {
constructor() {
super();
this.state = {someData: {}, myVar}
}
componentDidMount() {
myVar = myVar + 1;
myDataObj.myData.push({name:'Item 4'});
// someData.myData.push({name:'Item 4'}); this doesn't work... 'someData' is not defined
this.setState({someData: myDataObj, myVar});
}
render () {
return(
<div className="App">
{console.log(myVar)} {/* Logs a 2 then 3 */}
{console.log(this.state.myVar)} {/* Logs a 2 then 3 */}
{console.log(myDataObj.myData[3])} {/*Logs undefined then 'Item 4' */}
{/* {console.log(this.state.someData.myData[0])} */} {/*TypeError: Cannot read property '0' of undefined */}
</div>
);
}
}
export default App;
Upvotes: 1
Views: 122
Reputation: 851
About your first log statement, someData
is undefined because it is a state variable so it needs to be accessed as this.state.someData
. Still pushing items directly into the state is not a good practice. Just for the sake of your log statement, your state needs to be initialized like i have done below for it to run correctly.
this.state = {
someData: {
myData: []
},
myVar
}
This should solve your second log statement as well. Your state needs to be initialized as above if you want to log this.state.someData.myData[0]
on your first render because myData
array inside someData is not defined until your setState
in componentDidMount runs.
Upvotes: 1
Reputation: 530
You might want to checkout React's component lifecycle. State and Lifecycle
ComponentDidMount get's executed after mounting, e.g. after the component has been rendered once. During your first render this.state.someData.myData
is undefined. Accessing a property of undefined results in a TypeError.
Move your variable directly to your state:
this.state = {
myData: [
{name:'Item 1'},
{name:'Item 2'},
{name:'Item 3'}
],
myVar : 2
}
Upvotes: 2
Reputation: 534
Not sure why you are declaring variables outside the class and then using it as its state. I would do like :-
import React, {Component} from 'react';
import './App.css';
class App extends Component {
constructor() {
super();
this.state = {
myData: [{name:'Item 1'},
{name:'Item 2'},
{name:'Item 3'}],
myVar : 2}
}
componentDidMount() {
//myVar = myVar + 1;
// myDataObj.myData.push({name:'Item 4'});
// someData.myData.push({name:'Item 4'}); this doesn't work... 'someData' is not defined
this.setState({myData: [...this.state.myData, {"name" : 4}],
myVar : this.state.myVar + 1});
}
render () {
return(
<div className="App">
{console.log(this.state.myVar)}
{console.log(this.state.myData[3])}
</div>
);
}
}
export default App;
Upvotes: 2