how to access state variable in componentDidMount in reactjs - reactjs

"TypeError: Cannot read property 'state' of null"
the above error message is what i get....
following is my code
constructor(props) {
super(props)
this.state = {
desc: '',
}
}
componentDidMount = () => {
var ref = fire.database().ref("Employers/Employer1");
ref.orderByKey().on("child_added", function(snapshot) {
this.setState({
desc: snapshot.val()
})
console.log('====================================');
console.log(this.state.desc);
console.log(snapshot.val().Description);
console.log('====================================');
});
// snapshot.val() is the dictionary with all your keys/values from the '/store' path
}

This is because of this behavior in javascript. There are two ways to solve it. First to use arrow function, change third line to
ref.orderByKey().on("child_added", (snapshot) => {
other way is to assign value of this to another variable and use state by using that variable. forexample
const self = this;
ref.orderByKey().on("child_added", function(snapshot) {
this.setState({ desc: snapshot.val() })
console.log('====================================');
console.log(self.state.desc);
console.log(snapshot.val().Description);
console.log('====================================');
});
For understanding this you can read this article

componentDidMount is a life cycle hook, it need not be an arrow function.
change
componentDidMount = () => {
}
To
componentDidMount(){
}

Related

React.JS TypeError: Cannot read property 'number' of undefined - (inside setState)

Hello everyone,
In my ReactJS website I get this error - `TypeError: Cannot read property 'number' of undefined`
`HTMLInputElement.anonymous ` why ?
I did console.log(this.state.number) and number has a value in it.
class App extends Component {
constructor(props) {
super(props);
this.state = {
mobileNum: '',
number: '',
};
}
somefunction=()=>{ // Is called with onKeyDown - I checked it does.
this.setState({ number: document.getElementById('mySubmit').value });
enterPressed = () => {
const submit = document.getElementById('mySubmit');
submit.addEventListener('keyup', function (event) {
if (event.key === 'Enter') {
this.setState({ mobileNum: this.state.number }); // Here is the error line !
}
});
};
If I use setState with if condition in another function it will do error - setState is not a function
this.setState({ mobileNum: this.state.number }) is working also in a different fuction I made, but in enterPressed() isn't.
Thanks for the helpers :)
It should be a fat arrow function
enterPressed = () => {
const submit = document.getElementById('mySubmit');
submit.addEventListener('keyup', (event) => {
if (event.key === 'Enter') {
this.setState({
mobileNum: this.state.number
});
}
});
};
You never call someFunction() which is supposed to assign a number value to this.state.number. When you try to assign this.state.number to mobileNum, the value is still undefined.
Instead of using HTML selectors in this function, you can add two-way binding:
enterPressed = (e) => {
e.preventDefault();
let password = e.target.value();
this.setState({ ...this.state, mobileNum: password});
};

setState is not toggling values and returning undefined React

This maybe a repetitive question but I am still not able to figure out why setState is not able to toggle boolean values? Here are the functions:
constructor(props){
super(props)
this.state = {
isPlaying: false
}
}
playButtonClicked = () => {
this.setState((prevState) => ({
isPlaying: !prevState.isPlaying
}))
console.log("updating state....state is="+this.isPlaying) // Its printing undefined
this.togglePlayPause();
}
Here's the div:
<button id="play-pause" onClick={this.playButtonClicked}></button>
Please let me know if you find the mistake. Thanks in advance.
this.setState((prevState) => ({
isPlaying: !prevState.isPlaying
}), function() {
console.log("updating state....state is="+this.state.isPlaying)
});
Setstate is async give console log in a callback.

What is the better way to update other state variable which is dependent on another state variable while re-rendering?

The scenario is, after mounting the component, in event listener I am setting a state variable and other state variables are being set by making a rest call from backend.
so far what I did is I am using componentWillUpdate and making rest call and setting all the required states.
I tried using componentWillUpdate method to calculate and set other state variables. But its re-rendering multiple times. I guess I am definitely doing something wrong here.
export default class Person extends React.Component {
constructor(props, context) {
super(props, context);
this.state = {
name: this.props.name,
age: "",
country: ""
};
}
componentDidMount() {
this.setDerivedStates();
}
componentWillUpdate() {
this.setDerivedStates();
}
attachListner() {
document.addEventListner("customEvent", () => {
this.setState({ name: something });
});
}
setDerivedStates() {
FetchService.get("url1" + this.state.name).then(response =>
this.setState({ age: response.age})
);
FetchService.get("url2" + this.state.name).then(response =>
this.setState({ country: response.country })
);
}
render() {
return (
<div>
<p>{this.state.name}</p>
<p>{this.state.age}</p>
<p>{this.state.country}</p>
</div>
);
}
}
I want to re-render the component once with all the new state variables.
Please suggest how should I do it. which lifecycle method and how should I use to set all these states?
You can use Promise.all to batch the two fetches so you only have call this.setState once -
const [resp1, resp2] = await Promise.all([
FetchService.get("url1" + this.state.name);
FetchService.get("url2" + this.state.name);
]);
this.setState({ age: resp1.age, country: resp2.country });
Also, componentWillUpdate is considered unsafe and will be deprecated in the future. I would suggest using componentDidUpdate instead -
componentDidUpdate = (prevProps, prevState) => {
if (prevState.name !== this.state.name) {
this.setDerviedStates();
}
}
You can wrap both fetches in Promise.all which will wait for both Promises to resolve, if one fails you will have no access to any Promise/s that resolves successfully and the operation will throw an error.
Add componentDidUpdate to check if the name state has changed, if so refetch.
componentDidUpdate(prevProps, prevState) {
if (prevState.name !== this.state.name) {
this.setDerivedStates();
}
}
async setDerivedStates() {
const url = `url${this.state.name}`;
try {
const [age, country] = await Promise.all([
FetchService.getAge(url),
FetchService.getCountry(url),
]);
this.setState({ age, country });
} catch (e) {
console.log('something went wrong', e);
}
}

Why do i end up with an empty array in my state?

I am setting my array's state in the componentDidMount but can't understand why it shows up as empty on the mount.
constructor(props){
super(props);
this.state = {
currentGroup: this.props.currentGroup,
eventHold: [],
idHold: []
}
}
componentDidMount(){
const groupRef = firebase.database().ref('groups').child(this.state.currentGroup).child('events');
var tempIdHold =[];
groupRef.on('value', snapshot => {
snapshot.forEach(function(snap) {
tempIdHold.push(snap.key)
})
this.setState({
idHold: tempIdHold
});
console.log(tempIdHold)
console.log(this.state.idHold)
})
this.loadGroupEvents(this.state.idHold);
}
The first console.log shows a populated tempId array but the second console.log right underneath it shows an empty state.id array. Why?
Because this.setState is a async function.
So, you can use the callback in setState function
this.setState({
idHold: tempIdHold
}, () => {
console.log(tempIdHold)
console.log(this.state.idHold)
});
this.setState is asynchronous which takes a callback that will invoke after the operation is finished try adding it and see the result
this.setState(
{ idHold: tempIdHold },
// our updated state will be available in our callback
() => console.log(this.state.idHold)
);

In react, insert response array into setState

class Search extends React.Component {
constructor() {
super();
this.state = {
searchResult: {
"sr": []
}
}
this.handleChange = this.handleChange.bind(this);
this.onSubmit = this.onSubmit.bind(this);
this.setState = this.setState.bind(this)
}
onSubmit = formProps => {
console.log(formProps.searchItem);
cryptoSearch.searchNames(formProps.searchItem)
.then((names) =>
console.log(names),
this.setState({
sr: { names }
}),
console.log(this.state.sr)
) // [ 'BTC Lite', 'BTCMoon' ]
.catch(err => console.log(err))
};
handleChange(e) {
this.setState({ errorMessage: '' });
}
I want to use onsubmit function to display the search result from an api. I declared an array called sr in constructor, and onSubmit function, when I use a package(similar to axios) to get a names(response) array object, how can I insert the names array into sr array??
You can simply set in state while I am assuming names from the response is an array.
this.setState({
sr: names
},()=>{ console.log(this.state.sr);});
You can then verify in callback of setState as setState is an asynchronous type.
If names is an array and you want to update your sr property with this array you can use ES6 spread operator and set your state like that:
this.setState(prevState => ( {
searchResult: { ...prevState.searchResult, sr: names }
} )
);
If you set your state directly with sr like in your code you will loose other properties of searchResult and your state shape will change also something like this:
this.state = {
"sr": []
}
One other point is since setState is asynchronous if you console.log your state immediately after setting your state, you can't get healthy results. Instead use a callback for this:
this.setState(prevState => ( {
searchResult: { ...prevState.searchResult, sr: names }
} ), () => console.log(this.state.searchResult.sr)
);
or do not bother logging here with a callback and do it in your render method for logging purposes:
render(){
console.log(this.state.searchResult.sr);
return( .... )
}
If names is an array then you can set it to state as
onSubmit = formProps => {
console.log(formProps.searchItem);
cryptoSearch.searchNames(formProps.searchItem)
.then((names) =>
this.setState({
sr: names
}),
)
.catch(err => console.log(err))
};

Resources