关于reactjs:有没有办法在React中访问父组件实例?

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

我知道在React组件中能够像this.parent这样的东西并不是一种功能性的方法,而且我似乎无法在React组件实例上找到任何导致父级的属性,但我只是期待 能够在我需要的地方做一些自定义的事情。

在任何人浪费时间解释它不是功能性的React"方式"之前,了解我需要这个,因为我正在努力实现以下目标:

为Meteor的Spacebars模板引擎构建一个转换器,其渲染模型确实考虑了父组件/模板。

我已经构建了一个修改输出jsx的转换器来实现这一点。 我通过在所有组成的子组件中传入parent={this}来完成此操作。 然而,事实发生在我之后,我可能根本就不知道会给我一种方法来访问父组件实例而无需额外的转换修改。

任何提示将非常感激。


如果你需要从孩子那里访问父母的道具和功能,那没有什么不对。

关键是你不应该使用React内部和未记录的API。

首先,它们可能会改变(破坏你的代码),最重要的是,还有许多其他更清洁的方法。

将道具传递给儿童

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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>

工作实例

使用上下文(如果没有直接的父/子关系)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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,
}

工作实例


更新React 0.13及更新版本

Component._owner在React 0.13中已弃用,_currentElement不再作为this._reactInternalInstance中的键存在。因此,使用下面的解决方案抛出Uncaught TypeError: Cannot read property '_owner' of undefined

替代方案是,从React 16开始,this._reactInternalFiber._debugOwner.stateNode

你已经认识到这几乎不是一件好事,但我在这里重复一遍,因为那些不能很好地阅读这个问题的人:这通常是在React中完成任务的不正当方法。

公共API中没有任何内容可以让您获得所需内容。您可以使用React内部实现此功能,但由于它是私有API,因此可能随时中断。

我再说一遍:你几乎肯定不会在任何生产代码中使用它。

也就是说,您可以使用this. _reactInternalInstance获取当前组件的内部实例。在那里,您可以通过_currentElement属性访问元素,然后通过_owner._instance访问所有者实例。

这是一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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);

这是一个有效的JSFiddle示例:http://jsfiddle.net/BinaryMuse/j8uaq85e/


用React 16测试

我正在玩类似的东西使用上下文,对于读这个的人,对于大多数通常的情况,不建议访问父母!

我创建了一个持有者,在使用时,总是会在显示列表中引用第一个持有者,所以如果你愿意,它就是"父"。看起来像这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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;
}

然后使用它,你将反应组件传递给方法,如下所示:

1
2
3
4
5
6
7
8
9
10
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);

这样,导出函数的任何组件都会将其父级的持有者作为prop传入(如果层次结构中没有任何内容,则为null)。从那里你可以获得refToInstance。在安装完所有内容之前,它将是未定义的。