3

Im working with a react.js app, and I remember that I was able to pass a callback function from a child to a parent with pops, the thing is I cant achieve to do this again (I'd like to keep it simple, without Flux libraries):

So my parent App:

class App extends Component {
  constructor(props) {
   super(props);
 }

 showViewAction(viewToShow){
   console.log(viewToShow);
 }

  render() {
    return (
      <div>
        <AppMenu showView={this.showViewAction}/>
      </div>
    );
  }
}

And my child AppMenu:

class AppMenu extends Component{

  constructor(props) {
   super(props);
 }

  showCirculares(){
    this.props.showView("circulares");
  }

  render(){

    return(
    <div>
      <MenuButton onClick={this.showCirculares} buttonTitle="SomeOtherProp"/>
    </div>
    );
  }
}

Everything I try, I always get:

Cannot read property 'props' of undefined at showCirculares;

I know this will be resolved with a simple task, and that this is basic React.js stuff, its just that I cant find a solution for this!! What am I doing wrong?

Karlo A. López
  • 2,548
  • 3
  • 29
  • 56
  • What is `MenuButton`? Is that a button component you got from a library or did you make it yourself? – Andrew Oct 25 '17 at 18:54

3 Answers3

4

Looks like you need to bind the this context to your callback functions. Do so in the constructor function like so:

App

class App extends Component {
  constructor(props) {
   super(props);
   this.showViewAction = this.showViewAction.bind(this);
 }

 showViewAction(viewToShow){
   console.log(viewToShow);
 }

  render() {
    return (
      <div>
        <AppMenu showView={this.showViewAction}/>
      </div>
    );
  }
}

AppMenu

class AppMenu extends Component{

  constructor(props) {
   super(props);
   this.showCirculares = this.showCirculares.bind(this);
 }

  showCirculares(){
    this.props.showView("circulares");
  }

  render(){

    return(
    <div>
      <MenuButton onClick={this.showCirculares} buttonTitle="SomeOtherProp"/>
    </div>
    );
  }
}

Why? The short version is that unless you bind this, when your functions run the value of this is undefined. What you want is the context of the component instead, so you have to manually bind the functions to it.

jered
  • 11,220
  • 2
  • 23
  • 34
  • I don't think that is the case. `bind` is only necessary if you need to retain the parent's context. In this case, it's a simple `console.log` – Andrew Oct 25 '17 at 18:44
  • @Andrew for `showViewAction` you are correct, however I still believe it would be good practice to `bind` it since rarely are such functions completely static and separate from the component context. `showCirculares` absolutely needs to be bound since it's calling `this.props`. – jered Oct 25 '17 at 18:47
  • I agree 100% with your statement and it was something I was considering commenting on. But I think the problem he/she is having is much deeper than a simple `bind` that everyone is assuming. – Andrew Oct 25 '17 at 18:51
  • Thank you very much, now I understand better bind and arrow function callbacks. – Karlo A. López Oct 25 '17 at 19:00
  • @KarloA.López Your issue was resolved with `bind`? – Andrew Oct 25 '17 at 19:32
  • Yep, both `bind` and use arrow functions worked perfectly! – Karlo A. López Oct 25 '17 at 20:05
  • It must have been a problem with your `MenuButton` then. `App` wouldn't need the binding. But still good practice to have. – Andrew Oct 25 '17 at 20:36
1

You need to bind the showCirculares with the class so that it does not have this undefined. Following are the ways to do this.

Bind your method in constructor like this

constructor(props) {
   super(props);
   this.showCirculares = this.showCirculares.bind(this)
 }

  showCirculares(){
    this.props.showView("circulares");
  }

Or simply use arrow function like this

showCirculares = () => {
   this.props.showView("circulares");
}
Prakash Sharma
  • 15,542
  • 6
  • 30
  • 37
1

You can bind explicitly showCirculares using the bind function like @jered said, or you can use arrow functions, that are implicitly bound to the calling this.

<MenuButton onClick={() => this.showCirculares()} buttonTitle="SomeOtherProp"/>
Luke
  • 8,235
  • 3
  • 22
  • 36