首页 文章

有没有办法访问React中的父组件实例?

提问于
浏览
35

我知道在一个React组件中能够像 this.parent 这样的东西不是一种功能性的方法,我只是希望能够在我需要的地方做一些自定义的东西 .

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

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

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

任何提示将不胜感激 .

3 回答

  • 48

    Update for React 0.13 and newer

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

    另一种选择是,从React 16开始, this._reactInternalFiber._debugOwner.stateNode .


    你've already recognized that this is not a good thing to do almost always, but I'米在这里重复一遍,因为那些不能很好地阅读这个问题的人: this is generally an improper way to get things done in React.

    公共API中没有任何内容可以让您获得所需内容 . 您可以使用React内部结构来实现此目的,但因为's a private API it'可能会在 any time. 处破坏

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

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

    这是一个例子:

    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);
    

    这里是a working JSFiddle examplehttp://jsfiddle.net/BinaryMuse/j8uaq85e/

  • 0

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

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

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

    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

  • 47

    Tested with React 16

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

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

    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;
    }
    

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

    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 . 在安装所有东西之前,它将是未定义的 .

相关问题