从父调用子方法

新手上路,请多包涵

我有两个组件:

  1. 父组件

  2. 子组件

我试图从 Parent 调用 Child 的方法,我尝试过这种方式但无法得到结果:

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

有没有办法从 Parent 调用 Child 的方法?

注意:子组件和父组件位于两个不同的文件中。

原文由 N8FURY 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 831
2 个回答

首先,让我表达一下,这通常 不是 React 领域的处理方式。通常你想要做的是将功能传递给 props 中的子项,并在事件中传递子项的通知(或者更好的是: dispatch )。

但是,如果您 必须 在子组件上公开命令式方法,则可以使用 refs 。请记住,这是一个逃生舱口,通常表明有更好的设计可用。

以前,仅基于类的组件支持引用。

随着 React Hooks 的出现,情况不再如此

现代 React with Hooks ( v16.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() 的文档 在这里

useImperativeHandle 自定义使用 ref 时暴露给父组件的实例值。

使用类组件的旧版 API ( >= 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>

回调参考 API

回调样式的 refs 是实现此目的的另一种方法,尽管在现代 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>

原文由 rossipedia 发布,翻译遵循 CC BY-SA 4.0 许可协议

你可以在这里使用另一种模式:

 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 调用子项的 getAlert

如果您的孩子被 connect() 包裹,这也适用,因此您不需要 getWrappedInstance() hack。

请注意,您不能在父级中使用 onClick={this.clickChild} ,因为当渲染父级时,子级未安装,因此 this.clickChild 尚未分配。使用 onClick={() => this.clickChild()} 很好,因为当您单击按钮时 this.clickChild 应该已经分配。

原文由 brickingup 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题