54

I have a function that comes from a parent all the way down to a the child of a child in a component hierarchy. Normally this wouldn't be too much of a problem, but I need to receive a parameter from the child. I am currently getting this error message:

Uncaught (in promise) TypeError: this.props.myFunction is not a function.

Here is an example code to what I a doing:

class SomeComponent extends Component{

    constructor(props){
        super(props);
        //does whatever stuff        
        this.myFunction = this.myFunction.bind(this);

    }

    //(only applicable to raw and normal forms)
    myFunction(param){
        console.log('do something: ', param);
    }

    render(){
     return (<div><ChildComponent1 myFunction={()=>this.myFunction()}/></div>)
    }
}

class ChildComponent1{
      render(){
  return (<div><ChildComponent2 myFunction={()=>this.props.myFunction()}/></div>)
    }
}

class ChildComponent2{
      render(){
  return (<Button onClick={()=>this.props.myFunction(param)}>SomeButton</Button>)
    }
}

So just to sum it up: I am passing myFunction as a prop from SomeComponent all the way down to ChildComponent2, in which I want it called whenever a button is clicked and to pass a parameters from ChildComponent2.

Thanks!

1
  • The actual problem would probably be that your childComponent1 doesn't really forward any of the arguments that it might be called with, maybe you should refactor it in such a way that the function you are forwarding, isn't an arrow function in the end Commented Dec 28, 2016 at 20:57

3 Answers 3

80

I don't see why you would get that error, but you should be doing myFunction={this.myFunction} and myFunction={this.props.myFunction}:

class SomeComponent extends Component{

    constructor(props){
        super(props);
        //does whatever stuff        
        this.myFunction = this.myFunction.bind(this);

    }

    //(only applicable to raw and normal forms)
    myFunction(param){
        console.log('do something: ', param);
    }

    render(){
     return (<div><ChildComponent1 myFunction={this.myFunction}/></div>)
    }
}

class ChildComponent1{
      render(){
  return (<div><ChildComponent2 myFunction={this.props.myFunction}/></div>)
    }
}

class ChildComponent2{
      render(){
  return (<Button onClick={()=>this.props.myFunction(param)}>SomeButton</Button>)
    }
}

Wrapping the function call inside another (arrow) function is just unnecessary and won't forward the parameter properly (since all your intermediate arrow functions do not accept a parameter).

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

3 Comments

does that apply to a variable? and what if it's two levels down? also you made those as child classes but what if we're talking about exported/imported components?
I'm trying your solution but I have a Main.js and a Detail.js file, I'm trying to declare myFunction in Main and use it like this:this.props.myFunction(param), in my detail.js. But I get undefined for this.props.myFunction.
Would it be possible in react functional component?
19

An alternative and IMO more clean way to do it would be like this:

class SomeComponent extends Component{
    myFunction = param => {
        console.log('do something: ', param);
    }

    render(){
     return (
       <div>
         <ChildComponent1 onClick={this.myFunction}/>
       </div>)
    }
}

class ChildComponent1{
      render(){
        return (<div><ChildComponent2 onClick={this.props.onClick}/></div>)
      }
}

class ChildComponent2{
      render(){
        const { onClick } = this.props // destructure
        return (<Button onClick={()=>onClick(param)}>SomeButton</Button>)
      }
}

4 Comments

Seems there was some update to what 'myFunction = param => {' does that I can't find the new version of. Any ideas? No longer working.
Should param be defined inside ChildComponent2, e.g. var param ='ParamValue' ?
Yes that would be a correct way to do it. The answer is written the way the question was asked - so its assuming that you declare your param (like you suggest) or swap it out directly with the param when implementing it. My example will break if you use it directly.
So if you need to pass arguments to a function, put the expression within an anonymous function body.
4

In addition, with reatjs functional component.

export default function SomeComponent() {
  const myFunction = (param) => {
    console.log("do something: ", param);
  };
  return (
    <div>
      <ChildComponent1 yourFunction={myFunction} />
    </div>
  );
}

export function ChildComponent1({ yourFunction }) {
  return (
    <div>
      <ChildComponent2 parentFunction={yourFunction} />
    </div>
  );
}

export function ChildComponent2({ parentFunction }) {
  return <Button onClick={() => parentFunction(param)}>SomeButton</Button>;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.