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

3

64

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.

Uis answered 13/12, 2015 at 23:27 Comment(0)
D
66

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/

Decalcomania answered 13/12, 2015 at 23:43 Comment(8)
I used your great example in hereHotchpotch
Extremely useful information and ultimately helpful advice!Laundryman
In this case, if i have something after the call parent.doAThing() it seems it won't be executed. Is this always true?Bimetallic
While this answer is certainly the most correct for the question, be careful when using it. It's almost always a better idea to pass the doAThing function down to child as a prop rather than directly accessing a component's parent.Tamis
Also note that _debugOwner won't work with react's production buildWeatherboarding
work on Client but do not work on Server (in renderToString)Harneen
how to get the parent component name? in this way, only get the instanceSingle
In the react 17 _reactInternalInstance was renamed to _reactInternals, and the structure changed for a bitIntellection
R
78

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

Rahn answered 15/9, 2016 at 9:30 Comment(6)
Excellent! Still trying to grok React and this is exactly what I needed. I'd like to point out to others who may be struggling as I was that if you have made Child as a Class instead of a function, you'll be referring to this.fn in the onClick curlies, and the {fn} param may be omitted since it will arrive 'automagically' in the constructor as this.props.fn example hereGipson
how is the context example different from the first example using props? You are declaring contextTypes etc but you end up using props in the child right? I think the example needs to be changed?Itol
Thanks for your comment, Flion. The difference is that in the first example the Child gets the parent's function from the props ({ fn }) (first param), while in the second example the Child gets the parent's function from the context (props, { fn }) (second param). I hope this helps.Rahn
So, besides using a private API, imagine my components never get unmounted the structure remains and I implement a DOM like API for transverse the "component tree" . If in this kind of applications / mediums doing so is really helpful / solves problems, would you tc acceptabliy performance because being able to do so in this particular kind of apps / problem / mediums is very useful.I know people say this is "not the react way" or "not stateless app", but I'm still not understanding, what would be the problems / consequences of this design ? ThanksAnguish
this should be the selected answerBradway
How do you know which members or functions are React internal ?Adila
D
66

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/

Decalcomania answered 13/12, 2015 at 23:43 Comment(8)
I used your great example in hereHotchpotch
Extremely useful information and ultimately helpful advice!Laundryman
In this case, if i have something after the call parent.doAThing() it seems it won't be executed. Is this always true?Bimetallic
While this answer is certainly the most correct for the question, be careful when using it. It's almost always a better idea to pass the doAThing function down to child as a prop rather than directly accessing a component's parent.Tamis
Also note that _debugOwner won't work with react's production buildWeatherboarding
work on Client but do not work on Server (in renderToString)Harneen
how to get the parent component name? in this way, only get the instanceSingle
In the react 17 _reactInternalInstance was renamed to _reactInternals, and the structure changed for a bitIntellection
E
6

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.

Edouard answered 29/8, 2018 at 9:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.