我有两个组成部分。 html
我试图从父级调用孩子的方法,我尝试过这种方法,但没有获得结果 react
class Parent extends Component { render() { return ( <Child> <button onClick={Child.getAlert()}>Click</button> </Child> ); } } class Child extends Component { getAlert() { alert('clicked'); } render() { return ( <h1 ref="hello">Hello</h1> ); } }
有没有一种方法能够从父级调用子级的方法? git
注意:子组件和父组件位于两个不一样的文件中 github
首先,让我表示,这一般不是在React领域中解决问题的方法。 一般,您要作的是将功能传递给props中的子代,并传递事件中子代的通知(或者更好的是: dispatch
)。 ajax
可是,若是必须在子组件上公开命令式方法,则可使用refs 。 请记住,这是一个逃生舱口,一般表示可使用更好的设计。 app
之前,仅基于类的组件才支持引用。 随着React Hooks的出现,状况再也不如此 dom
>= react@16.8
) const { forwardRef, useRef, useImperativeHandle } = React; // We need to wrap component in `forwardRef` in order to gain // access to the ref object that is assigned using the `ref` prop. // This ref is passed as the second parameter to the function component. const Child = forwardRef((props, ref) => { // The component instance will be extended // with whatever you return from the callback passed // as the second argument useImperativeHandle(ref, () => ({ getAlert() { alert("getAlert from Child"); } })); return <h1>Hi</h1>; }); const Parent = () => { // In order to gain access to the child component instance, // you need to assign it to a `ref`, so we call `useRef()` to get one const childRef = useRef(); return ( <div> <Child ref={childRef} /> <button onClick={() => childRef.current.getAlert()}>Click</button> </div> ); }; ReactDOM.render( <Parent />, document.getElementById('root') );
<script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script> <div id="root"></div>
useImperativeHandle()
文档在这里 : ide
useImperativeHandle
自定义使用ref
时公开给父组件的实例值。 函数
>= react@16.4
) const { Component } = React; class Parent extends Component { constructor(props) { super(props); this.child = React.createRef(); } onClick = () => { this.child.current.getAlert(); }; render() { return ( <div> <Child ref={this.child} /> <button onClick={this.onClick}>Click</button> </div> ); } } class Child extends Component { getAlert() { alert('getAlert from Child'); } render() { return <h1>Hello</h1>; } } ReactDOM.render(<Parent />, document.getElementById('root'));
<script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script> <div id="root"></div>
<= react@16.3
) 出于历史目的,这是您在16.3以前的React版本中使用的基于回调的样式: 动画
const { Component } = React; const { render } = ReactDOM; class Parent extends Component { render() { return ( <div> <Child ref={instance => { this.child = instance; }} /> <button onClick={() => { this.child.getAlert(); }}>Click</button> </div> ); } } class Child extends Component { getAlert() { alert('clicked'); } render() { return ( <h1>Hello</h1> ); } } render( <Parent />, document.getElementById('app') );
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script> <div id="app"></div>
https://facebook.github.io/react/tips/expose-component-functions.html有关更多答案的参考,请参见此处。
经过查看“缘由”组件的引用,您正在破坏封装并使您没法仔细检查组件的全部使用位置就没法重构该组件。 所以,咱们强烈建议将ref视为组件的私有属性,就像state同样。
一般,数据应经过道具传递到树下。 有一些例外(例如,调用.focus()或触发一次不会真正“改变”状态的一次性动画),可是每当您公开称为“ set”的方法时,道具一般更好的选择。 尝试使其内部输入组件担忧其大小和外观,以便其祖先都不作。
您能够在此处使用其余模式:
class Parent extends Component { render() { return ( <div> <Child setClick={click => this.clickChild = click}/> <button onClick={() => this.clickChild()}>Click</button> </div> ); } } class Child extends Component { constructor(props) { super(props); this.getAlert = this.getAlert.bind(this); } componentDidMount() { this.props.setClick(this.getAlert); } getAlert() { alert('clicked'); } render() { return ( <h1 ref="hello">Hello</h1> ); } }
它的做用是在挂载子clickChild
时设置父项的clickChild
方法。 这样,当您单击父级中的按钮时,它将调用clickChild
,后者将调用子级的getAlert
。
若是您的孩子用connect()
包裹起来,那么这也能够工做,所以您不须要getWrappedInstance()
hack。
请注意,您不能在父级中使用onClick={this.clickChild}
,由于在渲染父级时未安装子级,所以还没有分配this.clickChild
。 使用onClick={() => this.clickChild()}
很好,由于单击按钮时this.clickChild
应该已经被分配了。
您能够进行继承反转(在此处查找: https : //medium.com/@franleplant/react-higher-order-components-in-depth-cf9032ee6c3e )。 这样,您就能够访问要包装的组件的实例(所以您将能够访问其功能)
若是只是由于您但愿子项为其父项提供可重用的特征而这样作,则能够考虑使用render-props来实现。
该技术实际上使结构颠倒了。 Child
如今包装了父级,所以我在下面将其重命名为AlertTrait
。 为了保持连续性,我保留了“ Parent
这个名称,尽管如今它实际上并非父代。
// Use it like this: <AlertTrait renderComponent={Parent}/> class AlertTrait extends Component { // You may need to bind this function, if it is stateful doAlert() { alert('clicked'); } render() { return this.props.renderComponent(this.doAlert); } } class Parent extends Component { render() { return ( <button onClick={this.props.doAlert}>Click</button> ); } }
在这种状况下,AlertTrait提供一个或多个特征,将其做为道具传递到其renderComponent
道具中给定的任何组件。
父级收到doAlert
做为道具,并能够在须要时调用它。
(为清楚起见,我在上面的示例中称为prop renderComponent
。可是在上面连接的React docs中,他们只是将其称为render
。)
Trait组件能够在其render函数中渲染围绕Parent的内容,但不会渲染Parent内部的任何内容。 实际上,若是它向父级传递了另外一个道具(例如renderChild
),则它能够在父级内部渲染事物,而后父级能够在其render方法中使用它。
这与OP要求的有所不一样,但有些人可能会像咱们同样最终来到这里(由于咱们这样作了),由于他们想建立可重用的特征,并认为子组件是实现此目标的好方法。