Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React: Cant call a function inside child component

I am trying to call a function inside child component through this.refs but i keep getting error that this function doesn't exist.

Uncaught TypeError: this.refs.todayKpi.loadTodaysKpi is not a function

Parent component:

class KpisHeader extends React.Component {

  constructor() {
    super();
    this.onUpdate = this.onUpdate.bind(this);
  }
    render(){
        return <div>
            <DateRange ref="dateRange" onUpdate={this.onUpdate}/>
            <TodayKpi ref="todayKpi" {...this.state}/>
          </div>;
    }

  onUpdate(val){

      this.setState({
          startDate: val.startDate,
          endDate: val.endDate
      }, function(){
        this.refs.todayKpi.loadTodaysKpi();
      });
  } 
 }

I want to get some data from DateRange component through function onUpdate, and then I want to trigger a function inside TodayKpi which fetches data from the server. For now it is just console.log("AAA");.

Child component:

class TodayKpi extends React.Component {
    constructor() {
        super();
        this.loadTodaysKpi = this.loadTodaysKpi.bind(this);
    }

    render(){
        console.log(this.props.startDate + " "+ this.props.endDate);
        return <div className="today-kpi">


          </div>;
    }
    loadTodaysKpi(){
        console.log("AAAA");
    }
}

How should I implement this?

like image 220
zazmaister Avatar asked Sep 10 '15 12:09

zazmaister


People also ask

How do you pass a function as a prop in React?

To pass a function as props in React TypeScript: Define a type for the function property in the component's interface. Define the function in the parent component. Pass the function as a prop to the child component.

How do you call parent function from child component?

To call a parent component method from the child component, we need to pass the changeName() method as a prop to the child component and access it as a props data inside the child component.


2 Answers

For reasons I don’t yet grasp, React discourages calling child methods from the parent. However, they relent and give us an ‘escape hatch’ which allows just that. You were correct in thinking that ‘Refs’ were a part of that escape hatch. If, like me, you have read dozens of articles searching for this information, you will be well prepared to understand their description of the escape hatch

In your case, you may want to try something like this in your KpisHeader class.

Change this line

<TodayKpi ref="todayKpi" {...this.state}/>

to use a ref callback function something like this:

<TodayKpi ref={(todayKpiComponent) => this.todayKpiComponent = todayKpiComponent} {...this.state}/>

or, pre-ES6, this:

<TodayKpi 
    ref= 
    {
        function (todayKpiComponent)
        {
            this.todayKpiComponent = todayKpiComponent      
        }
    }
    {...this.state}
 />

Then you will be able to access your todayKpi component methods from your KpisHeader class like this:

this.todayKpiComponent.someMethod();

Oddly, for me, inside the ref callback function, ‘this’ was the window rather than the parent component. So, I had to add

var self = this;

above the render method and use ‘self’ inside the ref callback function.

In my case I had an unknown number of dynamically generated children components, so I put each one into an array. I cleared the array in componentWillUpdate. It all seems to be working but I have an uneasy feeling especially given React’s distaste for calling children’s methods.

like image 147
Steve Steinitz Avatar answered Oct 04 '22 09:10

Steve Steinitz


If you want the function/method to be called inside the child, you should pass it to the child from the parent to start with. The other thing that you need to change is onUpdate to onChange, assuming that you want to track every change to that field. The other alternative is to check when it is onSubmit, but it sounds like you want to have it happen every time the field is updated.

like image 24
Hatem Jaber Avatar answered Oct 04 '22 10:10

Hatem Jaber