xunux
xunux

Reputation: 1769

Can a Child component Access its Containing Component's Methods?

I have seen similar questions to this but they are usually talking about a parent accessing a child component's methods or passing in methods through props. My question is on a specific situation, using props.children, and having any child component be able to call a method on the parent that is rendering props.children.

A simplified example of what im trying to achieve:

class WrapperComponent extends React.Component {

constructor(props){
    super(props);
    this.handleInputChange = this.handleInputChange.bind(this)
}

handleInputChange(e){
    console.log("neat, you changed the input")
}

render() {
    return (
        <form>
            {this.props.children}
        </form>
    )
  }
}

And the component that is calling said component and passing in the children as props.

const Component = (props) => {
return(
    <WrapperComponent>
        <div className="form-group" >
            <label>
                <div>Text</div>
                <input onChange={this.handleInputChange} type={"text"}/>
            </label>
        </div>
    </WrapperComponent>
)
}

The idea is that I can render a component that holds certain logic, and pass in the elements as children for that component to render, but also that the props.children can then call said logic within the wrapper, so I can pass in different children in different use cases, but the handling will always be the same. Is there a way to do this at all?

Upvotes: 2

Views: 140

Answers (2)

Yoav Kadosh
Yoav Kadosh

Reputation: 5155

Yes, there's a way, but its not straightforward, and you may want to consider a different approach.

In order for a child component to have access to the methods of an arbitrary parent, the parent must override the child's props. This can be done using React.cloneElement in the render() function of the parent. In your example:

class WrapperComponent extends React.Component {

constructor(props){
    super(props);
    this.handleInputChange = this.handleInputChange.bind(this)
}

handleInputChange(e){
    console.log("neat, you changed the input")
}

render() {
    return (
        <form>
            {React.Children.map(this.props.children, child => (
                React.cloneElement(child, {handleInputChange: this.handleInputChange}
            )}
        </form>
    )
  }
}

Then, you can access the method in the child via this.props.handleInputChange.

Upvotes: 1

Nick Swope
Nick Swope

Reputation: 331

You can clone your elements and add new props to them using some built-in React goodies:

class WrapperComponent extends React.Component {

constructor(props){
    super(props);
    this.handleInputChange = this.handleInputChange.bind(this)
}

handleInputChange(e){
    console.log("neat, you changed the input")
}

render() {
    return (
        <form>
            {React.Children.map(
                this.props.children, 
                el => React.cloneElement(el, {onInputChange: this.handleInputChange})
            )}
        </form>
    )
  }
}

Then (remove WrapperComponent):

const Component = (props) => {
  return(
        <div className="form-group" >
            <label>
                <div>Text</div>
                <input onChange={props.onInputChange} type={"text"}/>
            </label>
        </div>
  )
}

Then:

ReactDOM.render(
    <WrapperComponent><Component /></WrapperComponent>,
    document.getElementById('root')
)

Upvotes: 1

Related Questions