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?

1
  • What is MenuButton? Is that a button component you got from a library or did you make it yourself? Commented Oct 25, 2017 at 18:54

3 Answers 3

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.

Sign up to request clarification or add additional context in comments.

7 Comments

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 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.
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.
Thank you very much, now I understand better bind and arrow function callbacks.
@KarloA.López Your issue was resolved with bind?
|
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");
}

3 Comments

"Or simply use arrow function like this" It's not just about using an arrow function. The class field syntax (foo = bar;) is currently a proposal, it's not officially part of JavaScript yet.
@FelixKling I am assuming that OP is using babel transpiler. Wouldn't babel take care of this?
If it is configured correctly, yes.
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"/>

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.