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

IT技术 reactjs
2021-04-22 12:10:03

我知道这不是一种能够this.parent在 React 组件中执行类似操作的功能性方法,而且我似乎无法在 React 组件实例上找到任何指向父级的属性,但我只是希望能够在我需要的地方做一些自定义的事情。

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

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

我已经构建了一个转译器来修改输出 jsx 来实现这一点。我通过传入parent={this}所有组成的子组件来做到这一点然而,事后我突然想到,也许我根本不知道有什么东西可以让我在没有额外的转换修改的情况访问父组件实例

任何提示将不胜感激。

3个回答

如果您需要从孩子那里访问父母的props和功能,那没有错。

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

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

给孩子传递props

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>

工作示例

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

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

工作示例

这应该是选定的答案
2021-05-29 12:10:03
谢谢你的评论,弗利恩。不同之处在于,在第一个示例中,Child 从 props ({ fn })(第一个参数)中获取父级的函数,而在第二个示例中,Child 从上下文(props, { fn })(第二个参数)中获取父级的函数我希望这有帮助。
2021-06-05 12:10:03
优秀的!仍在尝试理解 React,这正是我所需要的。我想向可能像我一样挣扎的其他人指出,如果您将 Child 作为一个类而不是一个函数,您将this.fn在 onClick curl中引用,并且{fn}可以省略参数,因为它会作为示例, “自动”到达构造函数中this.props.fn
2021-06-10 12:10:03
上下文示例与第一个使用 props 的示例有何不同?您正在声明 contextTypes 等,但最终在孩子中使用道具,对吗?我认为这个例子需要改变?
2021-06-10 12:10:03
所以,除了使用私有 API 之外,想象一下我的组件永远不会被卸载,结构仍然存在,我实现了一个类似于 API 的 DOM 来横向“组件树”。如果在此类应用程序/媒体中这样做真的很有帮助/解决了问题,您是否会获得可接受的性能,因为能够在这种特定类型的应用程序/问题/媒体中这样做非常有用。我知道人们说这是“不反应方式”或“不是无状态的应用程序”,但我仍然不明白,这种设计会有什么问题/后果?谢谢
2021-06-17 12:10:03

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

下面是一个例子:

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/

我在这里用了你的好例子
2021-05-23 12:10:03
虽然这个答案对于这个问题来说肯定是最正确的,但在使用它时要小心。doAThing函数作为 prop传递给子组件而不是直接访问组件的父组件几乎总是更好的主意
2021-06-02 12:10:03
在这种情况下,如果我在通话后有一些东西,parent.doAThing()它似乎不会被执行。这总是真的吗?
2021-06-10 12:10:03
非常有用的信息和最终有用的建议!
2021-06-14 12:10:03
另请注意,_debugOwner这不适用于 react 的生产版本
2021-06-15 12:10:03

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

然后要使用它,您将在导出时将您的react组件传递给方法,如下所示:

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。但是,在安装所有内容之前,它将是未定义的。