How to call parent function from child prop React 15.5.0

Hello I tried to pass a function to the child class and call it from the child class, but the problem it is showing is undefined

Cannot read property "removeComment" from undefined

here are 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>
        );
    }
}

      

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();
        }
    }
}

      

+3


source to share


1 answer


the problem is you are losing your conflict 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 delete call ... however this

, which you bind does not have a react context with state and props

Several optimizations I would suggest ..

define your functions as inline lambdas so you don't have to call .bind (this) for 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 the way the functions are passed. Try to always avoid inline lambdas as element properties or class-responsive (in rendering). This will cause performance issues as the site becomes more complex.

eachComment = (elem, i) => {
    return (
        <Navbar key={i} index={i} editComment={this.editComment} removeComment={this.removeComment}>
          {elem}
        </Navbar>
    );
}

      

if you need to pass custom variables to functions that have been defined in a string, you can use .bind to pass them in instead of a lambda (binding is much more efficient than lambda ... aka

someList.map( (item, i) => <SomeElement onUserClick={this.handleUserClick.bind(null, item) />);

      

.bind()

The first argument is the context this

, you can pass null to avoid overriding the context. and then you can pass any other arguments to the function, which will be the arguments extended to the called call.

+2


source







All Articles