TypeError: this is undefined? - reactjs

I cannot reach this.state or I cannot setState inside the componentDidMount function. Why?
import React from 'react';
class LoginApi extends React.Component {
constructor(props) {
super(props);
this.state = {
formNames: [],
};
}
componentDidMount() {
let apiKey = '###';
window.JF.initialize({ apiKey: apiKey });
window.JF.login(
function success() {
window.JF.getForms(function(response) {
for (var i in response) {
this.setState({ formNames: [...this.state.formNames, response[i]] });
}
});
},
function error() {
window.alert('Could not authorize user');
}
);
}
render() {
return (
<div className="initializeForm">
<ul>
{this.state.formNames.map(forms => (
<li key={forms}>{forms}</li>
))}
</ul>
</div>
);
}
}
export default LoginApi;
When I have tried to this code I am getting TypeError: this is undefined.
this.setState({formNames: [...this.state.formNames,response[i]]});

Because you are referencing this within another function. When you create your callback function in JF.login and again in JF.getForms with the function keyword, it creates a new this context, hence why setState is undefined.
A common way to fix this is by using an arrow function (=>), which will end up using the this from its enclosing lexical scope, which in your case is the class.
window.JF.login(
() => {
window.JF.getForms((response) => {
for (var i in response) {
this.setState({ formNames: [...this.state.formNames, response[i]] });
}
});
},
() => {
window.alert('Could not authorize user');
}
);

Because you write the success function without bind / not as an arrow function. Without it, this refers to the calling function. In this case, to the success function. Change it to an arrow function and it will work. () => {...}

Related

Arrow function ambguity in ReactJS

class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
1000
);
}
componentWillUnmount() {
clearInterval(this.timerID);
}
tick() {
this.setState({
date: new Date()
});
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
In the above code - I wasn't able to understand the setInterval() line - to be precise the function argument of the setInterval line. I think it is an arrow function- I might be wrong. I replaced it with a regular function setInterval(function(){this.tick()},1000) and got an error saying tick() is not a function. What's happening here?
The this reference is reset when using old-style function() syntax, whereas with => (arrow-functions) the this reference is preserved. You can still use function() but you need to call .bind(this) to "fix" the this reference.
So this:
this.timerID = setInterval(
() => this.tick(),
1000
);
Is equivalent to this:
this.timerID = setInterval(
function() { this.tick(); }.bind(this),
1000
);
You need to do this because setTimeout/setInterval is a member-property of the global (window) object, so inside a setTimeout or setInterval callback the this reference is for window, not the call-site's this.

Unhandled Rejection (TypeError): Cannot read property 'setState' of undefined

I know that there are plenty of answers on this, for example this one. I did add the .bind(this) in the component constructor. I also tried the fat arrow method (fakeApiCall = ()=>{ ... }) but when I click Change Me, this error still displays:
import React, { Component } from 'react';
import axios from 'axios';
class App extends Component {
constructor(props){
super(props);
this.state = {
count : 1000
};
this.fakeApiCall = this.fakeApiCall.bind(this);
}
fakeApiCall (){
axios.get('https://jsonplaceholder.typicode.com/users')
.then(function(response){
// the response comes back here successfully
const newCount = response.data.length;
// fail at this step
this.setState({ count : Math.floor(newCount) });
});
}
render() {
return (
<div className="App">
<span style={{ fontSize : 66 }}>{this.state.count}</span>
<input type='button' onClick={this.fakeApiCall} value='Change me' />
</div>
);
}
}
export default App;
Your fakeApiCall function is bound to your context, but the function callback in axios is not.
To solve this, you can use an arrow function, as they automatically bind with your class. You can also do it for fakeApiCall and remove it's binding :
class App extends Component {
constructor(props) {
super(props);
this.state = {
count: 1000
};
}
fakeApiCall = () => {
axios.get('https://jsonplaceholder.typicode.com/users')
.then(response => { //This is an arrow function
const newCount = response.data.length;
this.setState({ count: Math.floor(newCount) });
});
}
render() {
return (
<div className="App">
<span style={{ fontSize: 66 }}>{this.state.count}</span>
<input type='button' onClick={this.fakeApiCall} value='Change me' />
</div>
);
}
}

ReactJS How do i call setState nested Functions

Lets say that i have this component:
export default class Test extends React.Component {
constructor(props) {
super(props);
this.state = {
test: false
};
}
func1 = () => {
function update() {
this.setState({ test: true }); // not working
}
};
render() {
return <div />;
}
}
As you see i have func1 which is in arrow form,and there is another function update in function update() form
So how do i call setState from inside function update as seen in example ?
EDIT:
the reason why i am trying to do something like this is i am using a game engine inside react component called phaser.So actually if i make update function as an arrow function for some reason phaser cant understand it and throws undefined error.update function is called 60 times in second
export default class Test extends React.Component {
constructor(props) {
super(props);
this.state = {
test: false
};
}
componentDidMount(){
this.func1()
}
func1 = () => {
var game = new Phaser.Game(canvas_width,canvas_height,Phaser.AUTO,'gameDiv',{ preload: preload, create: create, update: update });
function update() {
this.setState({ test: true }); // not working
}
};
render() {
return <div />;
}
}
SECOND EDIT:
THANKS GUYS WRITING update = update.bind(this) before var game solved it
You can use an arrow function again:
class Test extends React.Component {
constructor(props) {
super(props);
this.state = {
test: false
};
}
func1 = () => {
const update = () => {
this.setState({ test: true }) // not working
}
return update;
}
componentDidMount() {
this.func1()();
}
render() {
console.log( this.state);
return (
<div></div>
)
}
}
ReactDOM.render(<Test />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
When you use a regular function you lose the scope of this. When you use an arrow function you can use it without worrying about this as you do in your first function. But, instead of an arrow function that would work:
func1 = () => {
const that = this;
return function update() {
that.setState({ test: true }); // not working
}
}
Or even with bind as #Tholle suggested in his comment:
func1 = () => {
return ( function update() {
this.setState({ test: true }); // not working
}).bind(this);
}
Furthermore, you can define them separately and call the update function inside the func1.
func1 = () => {
this.update();
};
update() {
this.setState({ test: true }); // not working
}
This works too, because you are auto-binding your func1 function to this and your update function is invoked from there, keepin this scope.
you can pass this in as an argument, perhaps calling it self within the function. I.e self.setState. You could also bind or call the function passing the this as an argument. The important thing is that this still references the correct React component.
also, I'm a little confused why you're defining a function which returns a function like that. Could you just pass the function in point free form instead and not need to worry about this issue? You still need to bind the function to this..
export default class Test extends React.Component {
constructor(props) {
super(props);
this.func1 = this.func1.bind(this)
this.state = {
test: false
};
}
func1() {
this.setState({ test: true });
};
render() {
return <div callback={this.func1} />;
}
}

Cannot read property 'map' of undefined with REACTJS

I am new with reactjs.
This is what I am trying
class EventDemo extends Component {
constructor(){
super()
this.getStarWars()
this.state = {}
}
getStarWars = ()=> axios.get('https://swapi.co/api/people')
.then(res => {
console.log(res.data)
this.setState({
names: res.data.results
})
})
render() {
console.log(this.state.names);
return (
<div>
{this.state.names.map(function(e){
return <li>{e.name}</li>
})}
</div>
);
}
}
But This following error i am getting
What I am doing wrong here ? It supposed to work .
First of all,you shouldn't call your this.getStarWars() function inside the constructor, it is a very bad practice and could cause you troubles, http calls in React component should be generally called from the componentDidMount function.
However the issue in this case is another one,you haven't given an initial value to this.state.names, so when the component tries to do the initial render it fails because the names are undefined since the initial render appens before the http call is resolved
You code should be fixed like this:
class EventDemo extends Component {
constructor(){
super()
this.state = { names:[] }
}
componentDidMount(){
this.getStarWars()
}
getStarWars = ()=> axios.get('https://swapi.co/api/people')
.then(res => {
console.log(res.data)
this.setState({
names: res.data.results
})
})
render() {
console.log(this.state.names);
return (
<div>
{this.state.names.map(function(e){
return <li>{e.name}</li>
})}
</div>
);
}
}

react - handling promise without "ReduxPromise"

I'm trying to handle a promise without using "ReduxPromise".
return (
<div>
<div>{this.props.weatherData.then(response => {return response.data.city.name})}</div>
</div>
);
But I get this error :
bundle.js:1212 Uncaught Error: Objects are not valid as a React child (found: [object Promise]).
If I console.log(response.data.city.name), I do get a resulted string.
With ReduxPromise, I just have to do this :
const createStoreWithMiddleware = applyMiddleware(ReduxPromise)(createStore);
Then I only have to return this in the component :
<div>{this.props.weatherData.data.city.name}</div>
But I want to do it WITHOUT ReduxPromise
Without ReduxPromise, this.props.weatherData IS a promise. How do I handle this in the component ?
Doing this below does an infinite loop :
render(){
if (!this.props.weatherData) {
return <div></div>
};
this.props.weatherData.then(response => {
this.setState({ weatherData: response.data });
console.log(this.state.weatherData.city.name);
});
City name outputted infinitely.
You are attempting to render the return value of this.props.weatherData.then(...) in the jsx, which would be a promise, which is what the error message is telling you. Instead, fetch the data, put it in state, and render based off of that state.
Example:
class WeatherDataComp extends React.Component {
state = {
weatherData: null
}
componentDidMount() {
this.props.weatherData.then(response => {
this.setState({ weatherData: response.data })
})
}
render() {
if (!this.props.weatherData) {
return null
}
return (
<div>{this.state.weatherData.city.name}</div>
)
}
}
Thanks to #TLadd, I needed a lifecycle method, namely componentWillReceiveProps :
componentWillReceiveProps(nextProps) {
if (!nextProps.weatherData) {
return;
};
nextProps.weatherData.then(response => {
this.setState({ city: response.data.city.name });
});
}
Then :
render(){
if (!this.props.weatherData) {
return <div></div>
};
return (
<div>
<div>{this.state.city}</div>
</div>
);
}
And for the infinite loop, I'm pretty it's because of this :
setState causes the component to re-render, then the .then callback is called, so setState again, then re-render, etc.

Resources