I am getting the following error
Uncaught TypeError: Cannot read property 'setState' of undefined
even after binding delta in the constructor.
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = {
count : 1
};
this.delta.bind(this);
}
delta() {
this.setState({
count : this.state.count++
});
}
render() {
return (
<div>
<h1>{this.state.count}</h1>
<button onClick={this.delta}>+</button>
</div>
);
}
}
This is due to this.delta not being bound to this.
In order to bind set this.delta = this.delta.bind(this) in the constructor:
constructor(props) {
super(props);
this.state = {
count : 1
};
this.delta = this.delta.bind(this);
}
Currently, you are calling bind. But bind returns a bound function. You need to set the function to its bound value.
In ES7+ (ES2016) you can use the experimental function bind syntax operator :: to bind. It is a syntactic sugar and will do the same as Davin Tryon's answer.
You can then rewrite this.delta = this.delta.bind(this); to this.delta = ::this.delta;
For ES6+ (ES2015) you can also use the ES6+ arrow function (=>) to be able to use this.
delta = () => {
this.setState({
count : this.state.count + 1
});
}
Why ? From the Mozilla doc :
Until arrow functions, every new function defined its own this value [...]. This proved to be annoying with an object-oriented style of programming.
Arrow functions capture the this value of the enclosing context [...]
There is a difference of context between ES5 and ES6 class. So, there will be a little difference between the implementations as well.
Here is the ES5 version:
var Counter = React.createClass({
getInitialState: function() { return { count : 1 }; },
delta: function() {
this.setState({
count : this.state.count++
});
},
render: function() {
return (
<div>
<h1>{this.state.count}</h1>
<button onClick={this.delta}>+</button>
</div>
);
}
});
and here is the ES6 version:
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = { count : 1 };
}
delta() {
this.setState({
count : this.state.count++
});
}
render() {
return (
<div>
<h1>{this.state.count}</h1>
<button onClick={this.delta.bind(this)}>+</button>
</div>
);
}
}
Just be careful, beside the syntax difference in the class implementation, there is a difference in the event handler binding.
In the ES5 version, it's
<button onClick={this.delta}>+</button>
In the ES6 version, it's:
<button onClick={this.delta.bind(this)}>+</button>
You dont have to bind anything, Just use Arrow functions like this:
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 1
};
}
//ARROW FUNCTION
delta = () => {
this.setState({
count: this.state.count++
});
}
render() {
return (
<div>
<h1>{this.state.count}</h1>
<button onClick={this.delta}>+</button>
</div>
);
}
}
When using ES6 code in React always use arrow functions, because the this context is automatically binded with it
Use this:
(videos) => {
this.setState({ videos: videos });
console.log(this.state.videos);
};
instead of:
function(videos) {
this.setState({ videos: videos });
console.log(this.state.videos);
};
You have to bind your methods with 'this' (default object).
So whatever your function may be just bind that in the constructor.
constructor(props) {
super(props);
this.state = { checked:false };
this.handleChecked = this.handleChecked.bind(this);
}
handleChecked(){
this.setState({
checked: !(this.state.checked)
})
}
render(){
var msg;
if(this.state.checked){
msg = 'checked'
}
else{
msg = 'not checked'
}
return (
<div>
<input type='checkbox' defaultChecked = {this.state.checked} onChange = {this.handleChecked} />
<h3>This is {msg}</h3>
</div>
);
You can also use:
<button onClick={()=>this.delta()}>+</button>
Or:
<button onClick={event=>this.delta(event)}>+</button>
If you are passing some params..
if your are using ES5 syntax then you need to bind it properly
this.delta = this.delta.bind(this)
and if you are using ES6 and above you can use arrow function, then you don't need to use bind() it
delta = () => {
// do something
}
you have to bind new event with this keyword as i mention below...
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = {
count : 1
};
this.delta = this.delta.bind(this);
}
delta() {
this.setState({
count : this.state.count++
});
}
render() {
return (
<div>
<h1>{this.state.count}</h1>
<button onClick={this.delta}>+</button>
</div>
);
}
}
You need to bind this to the constructor and remember that changes to constructor needs restarting the server. Or else, you will end with the same error.
This error can be resolved by various methods-
If you are using ES5 syntax, then as per React js Documentation you
have to use bind method.
Something like this for the above example:
this.delta = this.delta.bind(this)
If you are using ES6 syntax,then you need not use bind method,you can
do it with something like this:
delta=()=>{
this.setState({
count : this.state.count++
});
}
There are two solutions of this issue:
The first solution is add a constructor to your component and bind your function like bellow:
constructor(props) {
super(props);
...
this.delta = this.delta.bind(this);
}
So do this:
this.delta = this.delta.bind(this);
Instead of this:
this.delta.bind(this);
The second solution is to use an arrow function instead:
delta = () => {
this.setState({
count : this.state.count++
});
}
Actually arrow function DOES NOT bind it’s own this. Arrow Functions lexically bind their context so this actually refers to the originating context.
For more information about bind function:
Bind function
Understanding JavaScript Bind ()
For more information about arrow function:
Javascript ES6 — Arrow Functions and Lexical this
Arrow function could have make your life more easier to avoid binding this keyword. Like so:
delta = () => {
this.setState({
count : this.state.count++
});
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Hello World</title>
<script src="https://unpkg.com/react#0.14.8/dist/react.min.js"></script>
<script src="https://unpkg.com/react-dom#0.14.8/dist/react-dom.min.js"></script>
<script src="https://unpkg.com/babel-standalone#6.15.0/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
class App extends React.Component{
constructor(props){
super(props);
this.state = {
counter : 0,
isToggle: false
}
this.onEventHandler = this.onEventHandler.bind(this);
}
increment = ()=>{
this.setState({counter:this.state.counter + 1});
}
decrement= ()=>{
if(this.state.counter > 0 ){
this.setState({counter:this.state.counter - 1});
}else{
this.setState({counter:0});
}
}
// Either do it as onEventHandler = () => {} with binding with this // object.
onEventHandler(){
this.setState({isToggle:!this.state.isToggle})
alert('Hello');
}
render(){
return(
<div>
<button onClick={this.increment}> Increment </button>
<button onClick={this.decrement}> Decrement </button>
{this.state.counter}
<button onClick={this.onEventHandler}> {this.state.isToggle ? 'Hi':'Ajay'} </button>
</div>
)
}
}
ReactDOM.render(
<App/>,
document.getElementById('root'),
);
</script>
</body>
</html>
Just change your bind statement from what you have to
=>
this.delta = this.delta.bind(this);
Adding
onClick={this.delta.bind(this)}
will solve the problem .
this error comes when we try to call the function of ES6 class ,
So we need to bind the method.
though this question had a solution already, I just want to share mine to make it be cleared, hope it could help:
/*
* The root cause is method doesn't in the App's context
* so that it can't access other attributes of "this".
* Below are few ways to define App's method property
*/
class App extends React.Component {
constructor() {
this.sayHi = 'hello';
// create method inside constructor, context = this
this.method = ()=> { console.log(this.sayHi) };
// bind method1 in constructor into context 'this'
this.method1 = this.method.bind(this)
}
// method1 was defined here
method1() {
console.log(this.sayHi);
}
// create method property by arrow function. I recommend this.
method2 = () => {
console.log(this.sayHi);
}
render() {
//....
}
}
Check state
check state whether you create particular property or not
this.state = {
name: "",
email: ""
}
this.setState(() => ({
comments: comments //comments not available in state
}))
2.Check the (this)
if you doing setState inside any function (i.e handleChange) check whether the function bind to this or the function should be arrow function .
## 3 ways for binding this to the below function##
//3 ways for binding this to the below function
handleNameChange(e) {
this.setState(() => ({ name }))
}
// 1.Bind while callling function
onChange={this.handleNameChange.bind(this)}
//2.make it as arrow function
handleNameChange((e)=> {
this.setState(() => ({ name }))
})
//3.Bind in constuctor
constructor(props) {
super(props)
this.state = {
name: "",
email: ""
}
this.handleNameChange = this.handleNameChange.bind(this)
}
If using inside axios , Use the Arrow(=>) in then
axios.get('abc.com').then((response) => {});
If anyone is looking for the same sulution when using axios, or any fetch or get, and using setState will return this error.
What you need to do, is to define the component outside, as so:
componentDidMount(){
let currentComponent = this;
axios.post(url, Qs.stringify(data))
.then(function (response) {
let data = response.data;
currentComponent.setState({
notifications : data.notifications
})
})
}
Related
This is a simple React app that I just generated with create-react-app, and modified only App.js to what you see below. This is an exercise to see if I understand bind enough to get results I expect as I toy with it. I'm not getting the expected result: I bind method in the class to obj, and use an onClick on a div to execute this bound method. In the method definition, I am calling this.setState, and setState is defined on obj, but I get an error that this.state is undefined in the setState method definition. Why?
import React from 'react';
import './App.css';
const Button = ({ onClick, quantity }) => <div onClick={onClick} style={{ width: 40 , height: 20}}>{quantity}</div>;
const generateButton = (quantity, onClick) => () => <Button onClick={() => onClick(quantity)} quantity={quantity} />
const obj = {
state: { count: 1000 },
setState: ({ count }) => this.state.count += count
};
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
}
this.method = this.method.bind(obj);
}
method(count) {
const newCount = this.state.count + count;
this.setState({ count: newCount})
}
render() {
return (
<div>
<div style={{width: 100, height: 100, fontSize: 50}}>{obj.state.count}</div>
{generateButton(10, this.method)()}
</div>
)
}
}
export default App;
When you use arrow functions, the context is taken from the nearest scope in which the function is defined. In your case, this would refer to the module scope.
From the docs
An arrow function does not have its own this. The this value of the enclosing lexical scope is used; arrow functions follow the normal variable lookup rules. So while searching for this which is not present in current scope, an arrow function ends up finding the this from its enclosing scope.
If you want the scope to remain relative to the object then use a standard function definition
setState: function({ count }) {
this.state.count += count;
}
when i try to use variable in my class function getting this error
Cannot read property 'zoomInIndex' of undefined
it is working fine if i have one function, can some one help me out how to use the variable in inner function or how to bind the inner function context?
class MyContainer extends Component {
constructor(props) {
super(props);
this.testClick = this.testClick.bind(this);
this.zoomClick = this.zoomClick.bind(this);
this.testVarible= "this is a test";
}
zoomClick(inout) {
return function(e) {
console.log(this.testVarible); // this is not working
}
}
testClick(){
console.log(this.testVarible);
}
}
if i use fat arrow functions it is working fine
zoomClick = inout => e => {
console.log(this.testVarible);
}
but i don't want to use fat arrow functions in react components since i ran into a lot of issues with my webpack configuration.
so my question is how to use the variable in inner function or how to bind the inner function context with out fat arrow syntax?
You need to bind the function returning from the zoomClick():
zoomClick(inout) {
return function(e) {
console.log(this.testVarible); // this is not working
}.bind(this); // <-- bind(this)
}
The anonymous function which was returned had no context of this and thus it was giving the error. Because zoomClick is already bound in the constructor, you just need to bind the function(e) { ... }
You can bind it to the class context one of two ways:
returnFunction = returnFunction.bind(this); or function() {}.bind(this).
class MyContainer extends React.Component {
constructor(props) {
super(props);
this.testClick = this.testClick.bind(this);
this.zoomClick = this.zoomClick.bind(this);
this.testVarible = "this is a test";
}
zoomClick(inout) {
let returnFunction = function(e) {
console.log(this.testVarible);
return this.testVarible;
};
returnFunction = returnFunction.bind(this);
return returnFunction;
}
testClick(){
console.log(this.testVarible);
}
render() {
return (
<div>{this.zoomClick(false)(false)}</div>
);
}
}
ReactDOM.render(
<MyContainer/>,
document.getElementById("react")
);
<div id="react"></div>
<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>
i don't want to use fat arrow functions in react components since i ran into a lot of issues with my webpack configuration
I'm guessing you tried to use class fields with the Babel plugin and that caused you some grief.
It's OK to use the traditional method of binding in the constructor and use arrow functions elsewhere in the code without running into those problems.
class MyContainer extends React.Component {
constructor(props) {
super(props);
this.zoomClick = this.zoomClick.bind(this);
this.testVarible = "this is a test";
}
zoomClick() {
return (e) => {
console.log(this.testVarible);
}
}
render() {
return <Button handleClick={this.zoomClick} />
}
}
function Button({ handleClick }) {
return <button onClick={handleClick()}>Click</button>
}
ReactDOM.render(
<MyContainer /> ,
document.getElementById('container')
);
<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="container"></div>
I am using a callback function selectionHandlerList() to set my state in Parent component (AudiobookList) from Child (AudiobookDetail). When I run the below code, I get this error message: "TypeError: this.setState is not a function".
When commenting out this.setState({ selectedAudiobook: someArg }) in my selectionHandlerList() function, I receive the expected value from the Child component (from console.log(someArg), so the callback must be working properly.
This is the code of my Parent component:
class AudiobookList extends Component {
constructor(props) {
super(props);
this.selectionHandlerList.bind(this);
}
state = {
audiobooks: [],
selectedAudiobook: null
}
componentWillMount() {
axios.get('http://www.demo.demo/api/get/all')
.then(response => this.setState({
audiobooks: response.data }))
.catch(e => console.log(e));
}
selectionHandlerList(someArg) {
this.setState({ selectedAudiobook: someArg });
console.log(someArg);
}
renderAudiobookChoice(audioBookChoice, selectionHandlerList) {
if (audioBookChoice === 'all') {
return (
this.state.audiobooks.map(audiobook =>
<AudiobookDetail
key={audiobook.id}
audiobook={audiobook}
selectionHandlerList={selectionHandlerList}
/>)
);
}
if (audioBookChoice === 'prose') {
return this.state.audiobooks.map(audiobook => {
return audiobook.text_type === 1 ?
<AudiobookDetail
key={audiobook.id}
audiobook={audiobook}
selectionHandlerList={selectionHandlerList}
/>
:
null;
});
}
if (audioBookChoice === 'poetry') {
return this.state.audiobooks.map(audiobook => {
return audiobook.text_type === 2 ?
<AudiobookDetail
key={audiobook.id}
audiobook={audiobook}
selectionHandlerList={selectionHandlerList}
/>
:
null;
});
}
}
render() {
console.log('ABL: ' + this.state.selectedAudiobook);
const selectionHandlerList = this.selectionHandlerList;
const { audioBookChoice } = this.props;
return (
<ScrollView>
{this.renderAudiobookChoice(
audioBookChoice,
selectionHandlerList
)}
</ScrollView>
);
}
}
export default AudiobookList;
I am under the impresseion, that the issue must be with binding this properly. But I am not able of figuring it out from related questions.
Any help is much appreciated.
Calling .bind on a function returns a new version of that function. You have called .bind, but you also have to reassign the function to the "bound" version of itself.
"TypeError: this.setState is not a function" is almost always caused by this simple error. Something like this should correct the issue:
constructor(props) {
super(props);
this.selectionHandlerList = this.selectionHandlerList.bind(this);
}
This part of the React docs explains more about why this is the case https://reactjs.org/docs/components-and-props.html#es6-classes
Another way of structuring your code which avoids this problem is to use an arrow function class property. For example:
selectionHandlerList = () => {
// this.[everything] works here, because `this`
//is preserved from outer scope within an arrow function
};
This feature still a proposal, but it does have babel support. You would need to enable transform-class-properties or enable stage-2 in Babel to use this syntax.
I'm having hard time understanding why the text won't change in browser or why it won't even console.log the new state. I'm just trying to change the text by clicking on it.
class Komponentti extends React.Component{
constructor(props){
super(props)
this.state = {teksti: "Hello"}
this.handleClick = this.handleClick.bind(this);
}
handleClick(){
this.setState = ({teksti: "Mello"}), function(){
console.log(this.state.teksti);
}
}
render(){
return(
<h1 onClick={this.handleClick}>{this.state.teksti}</h1>
)
}
}
You're calling it wrong. Should be:
handleClick() {
this.setState({teksti: "Mello"}), () => {
console.log(this.state.teksti);
}
}
May be you have been confused with es6 fat arrow functions.
In ES6 we can declare the functions using fat arrow notation to pass the lexical this to the function you declare.
Eg:
const example = () => {
// Something interesting
}
But we call that function as example().
But the setState() is an asynchronous function already declared in the React.
We can use it to update the state in the following manner.
handleClick(){
this.setState({teksti: "Mello"}), () => {
console.log(this.state.teksti);
}
}
Below are the way to set state :
this.setState({valuename:"value"});
this.state.varluename = "value";
this.forceUpdate();
I'm having trouble updating this code to use ECMAScript6 standards. I used to set getInitialState on a plain javascript object and pass it to the React.createClass API. I want to understand how can I rewrite the snippet below to use the recommended ES6 syntax for React components.
class App extends React.Component {
getInitialState: function () {
return {
tabList: tabList,
currentTab: 1
};
}
changeTab: function(tab) {
this.setState({ currentTab: tab.id });
}
render () {
return(
<div>
<Tabs currentTab={this.state.currentTab} tabList={this.state.tabList} changeTab={this.changeTab}/>
<Content currentTab={this.state.currentTab} />
</div>
);
}
}
In ES6 class style, you just assign initial state to this.state in the constructor:
constructor(props) {
super(props);
this.state = {
tabList: tabList,
currentTab: 1
};
}
See the docs:
Instead of providing a separate getInitialState method, you set up your own state property in the constructor.
Also note that, when using ES6 classes, handlers like changeTab won't be autobound, so you need to bind them explicitly, ideally in the constructor (this.changeTab = this.changeTab.bind(this)).
In ES6 it is recommended to use the following syntax:
class App extends React.Component {
constructor(props) {
super(props);
// Initialise your state here.
this.state = {
tabList: tabList,
currentTab: 1
};
// Bind your functions to this, avoiding scoping issues.
this.changeTab = this.changeTab.bind(this);
}
// Use function property syntax
changeTab(tab) {
this.setState({
currentTab: tab.id
});
}
render() {
// deconstruct your state.
const { currentTab, tabList } = this.state;
return(
<div>
<Tabs currentTab={currentTab} tabList={tabList} changeTab={this.changeTab}/>
<Content currentTab={currentTab} />
</div>
);
}
}