Hello I was trying to pass function to child class and call it from the child class but the problem it show the the function is undefined
Cannot read property 'removeComment' of undefined
here is my codes
parent class:
import React from 'react';
import Navbar from './notes';
export default class Board extends React.Component {
constructor(props, context) {
super(props, context);
this.state = {
comments: [
'Kingyyy',
'React',
'Learning'
]
};
}
removeComment() {
console.log(i);
var arr = this.state.comments;
arr.splice(i,1);
this.setState({comments: arr});
}
editComment(newtext, i) {
console.log(i);
var arr = this.state.comments;
arr[i] = newtext;
this.setState({comments: arr});
}
addComment() {
var text = prompt('enter the new ');
var arr = this.state.comments;
arr[arr.length] = text;
this.setState({comments: arr});
}
eachComment(elem, i) {
return (
<Navbar key={i} index={i} editComment={(newtext, i) => this.editComment.bind(this)} removeComment={(i) => this.removeComment.bind(this)}>
{elem}
</Navbar>
);
}
render() {
return (
<div>
<button onClick={this.addComment} className="btn btn-success">add new comment</button>
<br />
{
this.state.comments.map(this.eachComment)
}
</div>
);
}
}
the child class:
import React from 'react';
export default class Navbar extends React.Component {
edit() {
this.setState({
edit: !this.state.edit
})
}
save() {
var value = this.refs.newtext.value;
this.props.editComment(value,this.props.index);
this.setState({
edit: !this.state.edit
})
}
remove() {
this.props.removeComment(this.props.index);
}
constructor(props, context) {
super(props, context);
this.state = {edit: false};
}
normal() {
return (
<div>
<h1>{this.props.children}</h1>
<button className="btn btn-info" onClick={this.edit.bind(this)}>
edit
</button>
<button className="btn btn-danger" onClick={this.remove.bind(this)}>
remove
</button>
</div>
);
}
editing() {
return (
<div>
<textarea ref="newtext" defaultValue={this.props.children}></textarea>
<br/>
<button className="btn btn-success" onClick={this.save.bind(this)}>
save
</button>
</div>
);
}
render() {
if (this.state.edit) {
return this.editing();
} else {
return this.normal();
}
}
}
the issue is you are losing your react context. Change your constructor for the child class to this
constructor(props, context) {
super(props, context);
this.state = {edit: false};
this.normal = this.normal.bind(this)
this.editing = this.editing .bind(this)
}
you call .bind(this) on your remove call... however the this you are binding doesn't have the react context with state and props
A few optimizations I would suggest..
define your functions as inline lambdas so you dont have to call .bind(this) on every function every time... aka
edit = () => {
this.setState({
edit: !this.state.edit
})
}
save = () => {
var value = this.refs.newtext.value;
this.props.editComment(value,this.props.index);
this.setState({
edit: !this.state.edit
})
}
remove = () => {
this.props.removeComment(this.props.index);
}
normal = () => {
return (
<div>
<h1>{this.props.children}</h1>
<button className="btn btn-info" onClick={this.edit}>
edit
</button>
<button className="btn btn-danger" onClick={this.remove}>
remove
</button>
</div>
);
}
editing = () => {
return (
<div>
<textarea ref="newtext" defaultValue={this.props.children}></textarea>
<br/>
<button className="btn btn-success" onClick={this.save}>
save
</button>
</div>
);
}
in the parent class change how you pass the functions. Try to always avoid inline lambdas as properties on an element or react class (in the render). It will cause performance issues as the site gets more complex.
eachComment = (elem, i) => {
return (
<Navbar key={i} index={i} editComment={this.editComment} removeComment={this.removeComment}>
{elem}
</Navbar>
);
}
if you needed to pass custom variables to a function that were defined inline you can use .bind to pass them through instead of a lambda (bind is a lot more performant than a lambda... aka
someList.map( (item, i) => <SomeElement onUserClick={this.handleUserClick.bind(null, item) />);
.bind()'s first argument is the context this you can pass null to not override the context. and then you can pass any other arguments to the function to be arguments extended on the invoked call.
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