others-How to resolve the `Uncaught TypeError: Cannot read properties of undefined ` error in react.js applications
1. Purpose
In this post, I would demonstrate how to resovle the following error when I try to add a function to a react component:
Uncaught TypeError: Cannot read properties of undefined (reading 'updateCount')
at onClickResetButton (Counter.js:29)
at HTMLUnknownElement.boundFunc (ReactErrorUtils.js:63)
at Object.ReactErrorUtils.invokeGuardedCallback (ReactErrorUtils.js:69)
at executeDispatch (EventPluginUtils.js:83)
at Object.executeDispatchesInOrder (EventPluginUtils.js:106)
at executeDispatchesAndRelease (EventPluginHub.js:41)
at executeDispatchesAndReleaseTopLevel (EventPluginHub.js:52)
at Array.forEach (<anonymous>)
at forEachAccumulated (forEachAccumulated.js:22)
at Object.processEventQueue (EventPluginHub.js:252)
2. The solution
2.1 The origin code
Here is the code , I created a react component named Counter, user can click to increment or decrement the counter.
import React, { Component, PropTypes } from 'react';
const buttonStyle = {
margin: '10px'
};
class Counter extends Component {
constructor(props) {
super(props);
this.onClickIncrementButton = this.onClickIncrementButton.bind(this);
this.onClickDecrementButton = this.onClickDecrementButton.bind(this);
this.state = {
count: props.initValue
}
}
onClickIncrementButton() {
this.updateCount(true);
}
onClickDecrementButton() {
this.updateCount(false);
}
updateCount(isIncrement) {
const previousValue = this.state.count;
var newValue = isIncrement ? previousValue + 1 : previousValue - 1;
this.setState({count: newValue})
this.props.onUpdate(newValue, previousValue)
}
render() {
const {caption} = this.props;
return (
<div>
<button style={buttonStyle} onClick={this.onClickIncrementButton}>+</button>
<button style={buttonStyle} onClick={this.onClickDecrementButton}>-</button>
<span>{caption} count: {this.state.count}</span>
</div>
);
}
}
Counter.propTypes = {
caption: PropTypes.string.isRequired,
initValue: PropTypes.number,
onUpdate: PropTypes.func
};
Counter.defaultProps = {
initValue: 0,
onUpdate: f => f
};
export default Counter;
Here is the result:
You can click +
to add value, or click -
to decrement value.
Now I want to add some features to it.
2.2 Change the code and the problem occurs
I want to add a reset button to this component, if user click reset
button on the component, its value should be reset to 0.
Here is the code (Only changed parts included):
class Counter extends Component {
...
onClickResetButton() {
this.updateCount(false,true);
}
updateCount(isIncrement,isReset) { //add a parameter `isReset` to allow reset value
const previousValue = this.state.count;
var newValue = isIncrement ? previousValue + 1 : previousValue - 1;
if(isReset) { //If isReset is true, then reset the value
newValue = 0;
}
this.setState({count: newValue})
this.props.onUpdate(newValue, previousValue)
}
render() {
const {caption} = this.props;
return (
<div>
<button style={buttonStyle} onClick={this.onClickIncrementButton}>+</button>
<button style={buttonStyle} onClick={this.onClickDecrementButton}>-</button>
//add a button with a onClick prop to process the reset button onclick event
<button style={buttonStyle} onClick={this.onClickResetButton}>0</button>
<span>{caption} count: {this.state.count}</span>
</div>
);
}
}
You can see that I have changed the following lines:
-
Add a button to the
render()
function, to allow user click to reset. I passed a property to the button just like follows:onClick={this.onClickResetButton}
-
Then I add a function to process the onClick event like this:
onClickResetButton() { this.updateCount(false,true); }
-
Then I changed the original function to reuse it process the reset event:
updateCount(isIncrement,isReset) { //add a parameter `isReset` to allow reset value const previousValue = this.state.count; var newValue = isIncrement ? previousValue + 1 : previousValue - 1; if(isReset) { //If isReset is true, then reset the value newValue = 0; } this.setState({count: newValue}) this.props.onUpdate(newValue, previousValue) }
Now run the app:
$ npm run dev
I got this error :
Uncaught TypeError: Cannot read properties of undefined (reading 'updateCount')
at onClickResetButton (Counter.js:29)
at HTMLUnknownElement.boundFunc (ReactErrorUtils.js:63)
at Object.ReactErrorUtils.invokeGuardedCallback (ReactErrorUtils.js:69)
at executeDispatch (EventPluginUtils.js:83)
at Object.executeDispatchesInOrder (EventPluginUtils.js:106)
at executeDispatchesAndRelease (EventPluginHub.js:41)
at executeDispatchesAndReleaseTopLevel (EventPluginHub.js:52)
at Array.forEach (<anonymous>)
at forEachAccumulated (forEachAccumulated.js:22)
at Object.processEventQueue (EventPluginHub.js:252)
The core error message is:
Uncaught TypeError: Cannot read properties of undefined (reading 'updateCount')
at onClickResetButton (Counter.js:29)
The line 29 in Count.js is:
this.updateCount(false,true);
So the react.js compiler is complaining that it can not read updateCount
from this, so I think the problem is caused by this
.
2.3 The real solution #1
The problem is caused by the this
reference, this
can not be recoginized by default, except that you bind this
to the function you declared in the component.
So the solution is very simple, just add this line to the constructor of you component:
this.onClickResetButton = this.onClickResetButton.bind(this);
So now the constructor of Counter component is as follows:
constructor(props) {
super(props);
this.onClickIncrementButton = this.onClickIncrementButton.bind(this);
this.onClickDecrementButton = this.onClickDecrementButton.bind(this);
this.onClickResetButton = this.onClickResetButton.bind(this);
this.state = {
count: props.initValue
}
}
You can see that every function in the component that is calling this
should bind this
to allow the access.
2.4 The real solution #2
If you are tired of binding all functions to this
,you can just use arrow
function to bind this
automatically:
<button style={buttonStyle} onClick={()=>this.onClickResetButton()}>0</button>
If you choose this solution ,then the following line of code is NOT required, just comment it out:
//this.onClickResetButton = this.onClickResetButton.bind(this);
2.5 Run the app again
Now let’s run the react.js app again:
$ npm start
We got this:
It’s working!
3. Summary
In this post, I demonstrated how to solve the Uncaught TypeError: Cannot read properties of undefined (reading 'updateCount')
error when trying to add a function to a react component, the key point is that you should remember to call bind(this)
or use arrow function if you want to call this
in your new function . That’s it, thanks for your reading.