2

I want to simply call the a parent component function from a grandchild component.

Here is my grandchild:

var ReactDOM = require('react-dom');
var React = require('react');

class Button extends React.Component {
    constructor(props) {
        super(props);
        console.log(props);
        this.state = {
            options: props.options,
            showDropdown: false
        };
    }
componentWillMount() {
    var defaultFeatureOptionId = this.props.feature.DefaultFeatureOptionId;     
    var options = [...this.state.options]
    var isBigButton = false;
    options.forEach((option) => {
        if (option.Description.length > 8) {
            isBigButton = true;
        }
    });
    options.forEach((option) => {
        var classes = "";
        if (isBigButton) {
            classes = "option-button big-button hidden";
        } else {
            classes = "option-button small-button hidden";
        }
        if (option.Id === defaultFeatureOptionId) {
            classes = classes.replace("hidden", " selected");
        }
        option.class = classes;
    })
    this.setState({ options })
}
updateIllustration(value) {
    console.log(this.props.onClick);
    this.props.onClick(value);
}
toggleDropdown(index) {
    var options = [...this.state.options];
    var option = options[index];

    this.updateIllustration(option.Option);

    var showDropdown = !this.state.showDropdown;
    this.setState({
        showDropdown: showDropdown
    })
    options.forEach((opt) => {
        opt.class = opt.class.replace("selected", "");
        opt.class = opt.class.replace("hidden", "");
        if (opt.Id !== option.Id && this.state.showDropdown) {
            opt.class += " hidden";
        }
        if (opt.Id === option.Id) {
            opt.class += "selected";
        }
    });
    this.setState({ options })
}
render() {
    if (this.state.options) {
        return (<div> {
            this.state.options.map((option, index) => {
                return <div className={option.class} key={option.Id} onClick={() => this.toggleDropdown(index)}>
                    <div> {option.Description}</div>
                    <img className="option-image" src={option.ImageUrl}></img>
                    <i className={(this.state.showDropdown ? 'hidden' : ' fa fa-chevron-down') } aria-hidden="true" onClick={() => this.toggleDropdown(index)}></i>
                </div>
            })
        }

        </div>
        )
    }
    else {
        return <div>No options defined</div>
    }
}
}

module.exports = Button;

Here is the child component:

var ReactDOM = require('react-dom');
var React = require('react');
var Button = require('./button');
var Slider = require('./slider');

class Option extends React.Component {
constructor(props) {
    super(props);
}
updateIllustration(value) {
    this.props.onClick(value);
}
render() {       
    if (this.props.type.Id === 1) {
        return <div className="option"> <Button options={this.props.options} feature={this.props.feature} onClick={() => this.props.onClick} /></div>
    }
    if (this.props.type.Id === 2) {
        return <div className="option"> <Slider options={this.props.options} feature={this.props.feature} onClick={() => this.props.onClick}/></div>
    }
    else {
       return <div> No option type defined </div>
    }
}
}

module.exports = Option;

And here is the final parent component:

 var ReactDOM = require('react-dom');
 var React = require('react');
 var ConfigurationService = require('../configurationService');
 var Option = require('./option');

 class Feature extends React.Component {
     constructor(props) {
    super(props);
    this.state = {
        features: null
    };
    this.getConfiguration();

}   
updateIllustration(object) {
    console.log("MADE IT BACK");
    console.log(object);
}
getConfiguration() {
    var self = this;
    var config = ConfigurationService.getConfiguration('NORMSTAHL', 'SUPERIOR').then(function (config) {
        console.log("TJE");
        console.log(config.data);
        self.setState({ features: config.data.Features })
    });       
}
render() {
    if (this.state.features) {
        return (<div className="feature-component-container"> {
            this.state.features.map(function (feature) {
                return <div className="feature" key={feature.Id}>
                    <div className="feature-header">{feature.Description} </div>{
                        <Option options={feature.FeatureOptions} type={feature.Type} feature={feature} onClick={() => this.updateIllustration } />
                    }                    
                </div>
            })
        }
        </div>)
    }
    else {
        return <div>no data</div>
    }
}
 }

 module.exports = Feature;

The function i want to call is the updateIllustration function and right now i don't get any errors but it simply wont get all the way back to console.log("MADE IT BACK"); I have read a about a way to do it with a context but everyone says it works but it's not recommended. So what is the recommended way of doing it?

1 Answer 1

2

Its a name mismatch issue, In parent you are passing the function by onClick name so in child you need to use this.props.onClick instead of this.props.updateIllustration. updateIllustration is name of actual function and you are passing that function by different name.

Use this in Child Component:

<Button 
    options={this.props.options} 
    feature={this.props.feature} 
    onClick={() => this.props.onClick()} />

Update:

You need to call that function.

In Parent Component:

<Option ... onClick={() => this.updateIllustration() } /> //here use ()

In Child Component:

<Button ... onClick={() => this.props.onClick()} /> //here use ()

You forgot to bind the context in map, to solve that issue use arrow function like you are using other places:

this.state.features.map( (feature) => {
Sign up to request clarification or add additional context in comments.

4 Comments

it still doesn't get to the parent function. :/
now i get "Uncaught TypeError: Cannot read property 'updateIllustration' of undefined" on this row: onClick={() => this.updateIllustration() } in the parent component
because you forgot to bind the context in map, use arrow function like this: this.state.features.map( (feature) => {
YEEES! :) That was it :) Thank you so much :)

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.