I'm making very simple react app. Yet as I try to invoke method of parent (actually grandparent) component via onChange event, I keep getting Uncaught TypeError: Cannot read property 'props' of undefined
.
Here is the component/form that is triggering the event (thus invoking method on binded parent component... Yes I used .bound(this) on the method as I passed it down from parent component via props.).
class MonthsTable extends Component { handleChangeOnMonth(e){ this.props.setMonth(e.target.id, e.target.value); // here the method is not found, causing error. } render(){ console.log(this.props.setMonth) // here the method is present alright return (<form> {this.props.months.map((e, i) => <input type='number' id={i} key={i} // yes I know, bad habit, but in this case it doesn't matter value={this.props.months[i]} onChange={this.handleChangeOnMonth} />)} </form>) } }
Here is how I pass the method as props from most parent (grandparent) component.
<Months setMonth={this.setMonth.bind(this)} />
Here is how I pass the method as props in the parent (the component that is between method owner and method invoker)
<MonthsTable setMonth={this.props.setMonth} />
And finally passed to component (MonthsTable) that you saw first. Wheter it is relevant or not, final (most child) components is displayed depending of if statement which works just fine (Might somehow be relevant, I don't know).
Question is... Why is the (setMonth) method 'invisible' inside of (handleChangeOnMonth) method.
Thanks for any advice.
What Causes TypeError: Cannot Read Property of Undefined. Undefined means that a variable has been declared but has not been assigned a value. In JavaScript, properties and functions can only belong to objects.
The "Cannot read property 'includes' of undefined" error occurs when calling the includes() method on an undefined value. To solve the error, make sure to only call the includes() method on data types that support it - arrays and strings.
The React. js "Uncaught TypeError: X is not a function" occurs when we try to call a value that is not a function as a function, e.g. calling the props object instead of a function. To solve the error, console. log the value you are calling and make sure it is a function. Here is an example of how the error occurs.
Components are independent and reusable bits of code. They serve the same purpose as JavaScript functions, but work in isolation and return HTML. Components come in two types, Class components and Function components, in this tutorial we will concentrate on Function components.
This means that when react runs our useState ( []) call, it will return us with Which means that in the first render of our component, react will “see” our items as an empty array, so instead of running undefined.map (...) like before, it will run [].map (...).
The variable you are trying to map over is undefined. It will probably eventually be an array, but due to the asynchronous nature of React, you are experiencing at least one render when the variable is undefined.
The issue Cannot read the property of undefined is quite common in JavaScript. When the variable is not defined, JavaScript can not read the undefined variable or property. A similar issue we can find in React JS.
React will run all effects after the render is committed to the screen, which means we can’t avoid a first render without our data. One possible solution is to give your variable a default initial value, with useState it would look like that: This means that when react runs our useState ( []) call, it will return us with
The actual problem here is that the this
context is not defined in your handleChangeOnMonth
function. This is caused because of the way that javascript handles the contexts of functions, basically when calling functions if you are not calling them directly from the object, and they are not bound they will not have a defined context, and since you are passing the function as a parameter to the input component, it loses the context.
The simplest way to fix this is to bind the function, I suggest that you bind the function in the constructor, like so:
class MonthsTable extends Component { constructor(props, context){ super(props, context); this.handleChangeOnMonth = this.handleChangeOnMonth.bind(this); } handleChangeOnMonth(e){ this.props.setMonth(e.target.id, e.target.value); } render(){ return (<form> {this.props.months.map((e, i) => <input type='number' id={i} key={i} value={this.props.months[i]} onChange={this.handleChangeOnMonth} />)} </form>) } }
alternatively if you are using decorators you could use the core-decorators
package to do this in a more elegant way:
import {autobind} from "core-decorators" @autobind class MonthsTable extends Component { handleChangeOnMonth(e){ this.props.setMonth(e.target.id, e.target.value); } render(){ return (<form> {this.props.months.map((e, i) => <input type='number' id={i} key={i} value={this.props.months[i]} onChange={this.handleChangeOnMonth} />)} </form>) } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With