is there any way to access the parent component instance in React?

Reactjs

Reactjs Problem Overview


I know it's not a functional approach to be able to do something like this.parent in a React component, and I can't seem to find any properties on a React component instance that lead to the parent, but I'm just looking to be able to do some custom things where I need this.

Before anyone wastes their time explaining it's not the functional React "way," understand that I need this because of the following I'm trying to achieve:

Build a transpiler for Meteor's Spacebars templating engine, whose rendering model does take into consideration parent components/templates.

I've already built a transpiler that modifies the output jsx to achieve this. I do this by passing in parent={this} in all child components composed. However, after the fact it occurred to me that maybe I simply don't know of something that will give me a way to access the parent component instance without additional transpilation modifications.

Any tips would be much appreciated.

Reactjs Solutions


Solution 1 - Reactjs

There's nothing wrong if you need to access the parent's props and functions from the children.

The point is that you should never use React internals and undocumented APIs.

First of all, they are likely to change (breaking your code) and, most importantly, there are many other approaches which are cleaner.

Passing props to children

class Parent extends React.Component {
    
    constructor(props) {
        super(props)
        
        this.fn = this.fn.bind(this)
    }
    
    fn() {
        console.log('parent')
    }
    
    render() {
        return <Child fn={this.fn} />
    }
    
}

const Child = ({ fn }) => <button onClick={fn}>Click me!</button>

Working example

Using context (if there's no direct parent/child relation)

class Parent extends React.Component {
    
    constructor(props) {
        super(props)
        
        this.fn = this.fn.bind(this)
    }
    
    getChildContext() {
        return {
            fn: this.fn,
        }
    }
    
    fn() {
        console.log('parent')
    }
    
    render() {
        return <Child fn={this.fn} />
    }
    
}

Parent.childContextTypes = {
    fn: React.PropTypes.func,
}

const Child = (props, { fn }) => <button onClick={fn}>Click me!</button>

Child.contextTypes = {
    fn: React.PropTypes.func,
}

Working example

Solution 2 - Reactjs

Update for React 0.13 and newer

Component._owner was deprecated in React 0.13, and _currentElement no longer exists as a key in this._reactInternalInstance. Therefore, using the solution below throws Uncaught TypeError: Cannot read property '_owner' of undefined.

The alternative is, as of React 16, this._reactInternalFiber._debugOwner.stateNode.


You've already recognized that this is not a good thing to do almost always, but I'm repeating it here for people that don't read the question very well: this is generally an improper way to get things done in React.

There's nothing in the public API that will allow you to get what you want. You may be able to get to this using the React internals, but because it's a private API it's liable to break at any time.

I repeat: you should almost certainly not use this in any sort of production code.

That said, you can get the internal instance of the current component using this. _reactInternalInstance. In there, you can get access to the element via the _currentElement property, and then the owner instance via _owner._instance.

Here's an example:

var Parent = React.createClass({
  render() {
	  return <Child v="test" />;
  },

  doAThing() {
    console.log("I'm the parent, doing a thing.", this.props.testing);
  }
});

var Child = React.createClass({
  render() {
    return <button onClick={this.onClick}>{this.props.v}</button>
  },

  onClick() {
    var parent = this._reactInternalInstance._currentElement._owner._instance;
    console.log("parent:", parent);
    parent.doAThing();
  }
});

ReactDOM.render(<Parent testing={true} />, container);

And here's a working JSFiddle example: http://jsfiddle.net/BinaryMuse/j8uaq85e/

Solution 3 - Reactjs

Tested with React 16

I was playing around with something similar using context, tho to anyone reading this, for most usual cases, accessing the parent is not advised!

I created a holder that when used, would always have a reference to the first holder up the display list, so its 'parent' if you will. Looked something like this:

const ParentContext = React.createContext(null);

// function to apply to your react component class
export default function createParentTracker(componentClass){

    class Holder extends React.PureComponent {

        refToInstance

        render(){
            return(
                <ParentContext.Consumer>
                {parent => {
                    console.log('I am:', this, ' my parent is:',parent ? parent.name : 'null');
                    return(
                        <ParentContext.Provider value={this}>
                            <componentClass ref={inst=>refToInstance=inst} parent={parent} {...this.props} />
                        </ParentContext.Provider>
                    )}
                }
                </ ParentContext.Consumer>
            )
        }
    }

    // return wrapped component to be exported in place of yours
    return Holder;
}

Then to use it you would pass your react component to the method when you export it like so:

class MyComponent extends React.Component {

    _doSomethingWithParent(){
        console.log(this.props.parent);  // holder
        console.log(this.props.parent.refToInstance);  // component
    }
}

// export wrapped component instead of your own
export default createParentTracker(MyComponent);

This way any component exporting the function will get its parent's holder passed in as a prop (or null if nothing is further up the hierarchy). From there you can grab the refToInstance. It will be undefined until everything is mounted though.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionfaceyspacey.comView Question on Stackoverflow
Solution 1 - ReactjsMichele BertoliView Answer on Stackoverflow
Solution 2 - ReactjsMichelle TilleyView Answer on Stackoverflow
Solution 3 - ReactjsJames TrickeyView Answer on Stackoverflow