0

Following is the jsx code of child & parent parent react components. I am trying to pass the data from child react component to parent react component as property (generateReport) but it throws the error as

Uncaught TypeError: this.props.generateReport is not a function at MetricsReport.generateReport (metrics-report.jsx:40)

child.jsx

import React, { Component } from 'react';
import {
  Row,
  Col,
  Input,
  Collapsible,
  CollapsibleItem
} from 'react-materialize';

class MetricsReport extends Component {
  constructor(props) {
    super(props);
    this.state = {
      metricsParams: { reportType: '' }
    };
    this.getReportType = this.getReportType.bind(this);
    // Add the below line as per the answer but still facing the problem
    this.generateReport = this.generateReport.bind(this);
  }
  getReportType(event) {
    console.log(this.state.metricsParams);
    let metricsParams = { ...this.state.metricsParams };
    metricsParams.reportType = event.target.value;
    this.setState({ metricsParams });
  }

  generateReport() {
    this.props.generateReport(this.state.metricsParams);
  }
  componentDidMount() {}

  render() {
    return (
      <div class="ushubLeftPanel">
        <label>{'Report Type'}</label>
        <select
          id="metricsDropDown"
          className="browser-default"
          onChange={this.getReportType}
        >
          <option value="MetricsByContent">Metrics By Content</option>
          <option value="MetricsByUser">Metrics By User</option>
        </select>
        <button onClick={this.generateReport}>Generate Report</button>
      </div>
    );
  }
}

export default MetricsReport;

parent.jsx

import React, { Component } from 'react';
import MetricsReport from '../components/pages/metrics-report';

class MetricsReportContainer extends Component {
  constructor(props) {
    super(props);
    this.generateReport = this.generateReport.bind(this);
  }
  generateReport(metricsParams) {
    console.log(metricsParams);
  }
  componentDidMount() {}
  render() {
    return (
      <div>
        <MetricsReport generateReport={this.generateReport} />
      </div>
    );
  }
}

export default metricsReportContainer;
You Nguyen
  • 9,961
  • 4
  • 26
  • 52
Prem
  • 5,685
  • 15
  • 52
  • 95
  • bind `generateReport` function as you have done for `getReportType` – Agney Oct 07 '18 at 04:53
  • Possible duplicate of [ReactJS with ES6: this.props is not a function when I communicate two components](https://stackoverflow.com/questions/31141444/reactjs-with-es6-this-props-is-not-a-function-when-i-communicate-two-components) – Agney Oct 07 '18 at 05:00
  • I have done as per suggestion: `this.generateReport = this.generateReport.bind(this);` But still throwing the same error – Prem Oct 07 '18 at 05:04
  • 2
    I have done similar implementation and its working fine. Please have a look. https://codesandbox.io/s/kk89834r3o – Shantiswarup Tunga Oct 07 '18 at 06:36

2 Answers2

0

You forgot to bind the context this inside child component MetricsReport:

// inside the constructor
this.generateReport = this.generateReport.bind(this);

But you may simply use like this:

<button 
  onClick={this.props.generateReport(this.state.metricsParams)}
>
  Generate Report
</button>
Bhojendra Rauniyar
  • 83,432
  • 35
  • 168
  • 231
0

You can handle these scenarios by using anonymous functions instead of normal function. Anonymous function handles your this and removes the need to binding.

generateReport(metricsParams) { console.log(metricsParams); }

becomes

generateReport = (metricsParams) => { console.log(metricsParams); }

Also in child class

generateReport() { this.props.generateReport(this.state.metricsParams); }

becomes

generateReport = () => { var metricsParams = this.state.metricsParams; this.props.generateReport(metricsParams); }

Nikhil Pathania
  • 812
  • 6
  • 19