我有两个组成部分:

父组件 子组件

我试图从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>
    );
  }
}

是否有一种方法从父调用子方法?

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


当前回答

您可以使用ref从父组件调用子组件的函数

功能组件解决方案

在函数组件中,你必须使用useImperativeHandle来获取引用到如下所示的子组件中

import React, { forwardRef, useRef, useImperativeHandle } from 'react';
export default function ParentFunction() {
    const childRef = useRef();
    return (
        <div className="container">
            <div>
                Parent Component
            </div>
            <button
                onClick={() => { childRef.current.showAlert() }}
            >
            Call Function
            </button>
            <Child ref={childRef}/>
        </div>
    )
}
const Child = forwardRef((props, ref) => {
    useImperativeHandle(
        ref,
        () => ({
            showAlert() {
                alert("Child Function Called")
            }
        }),
    )
    return (
       <div>Child Component</div>
    )
})

类组件解决方案

Child.js

import s from './Child.css';

class Child extends Component {
 getAlert() {
    alert('clicked');
 }
 render() {
  return (
    <h1>Hello</h1>
  );
 }
}

export default Child;

Parent.js

class Parent extends Component {
 render() {
  onClick() {
    this.refs.child.getAlert();
  }
  return (
    <div>
      <Child ref="child" />
      <button onClick={this.onClick}>Click</button>
    </div>
  );
 }
}

其他回答

对于功能组件,最简单的方法是

父组件

parent.tsx

import React, { useEffect, useState, useRef } from "react";
import child from "../../child"

const parent: React.FunctionComponent = () => {
  const childRef: any = useRef();
}

const onDropDownChange: any = (event): void => {
    const target = event.target;
    childRef.current.onFilterChange(target.value);
};

return <child ref={childRef} />

export default parent;

子组件

child.tsx

import React, {   useState,   useEffect,   forwardRef,   useRef,   useImperativeHandle, } from "react";

const Child = forwardRef((props, ref) => {
 useImperativeHandle(ref, () => ({
    onFilterChange(id) {
      console.log("Value from parent", id)
    },
  }));
})

Child.displayName = "Child";

export default Child;

我希望我没有重复上面的内容但是如果传递一个回调道具来设置父类中的函数呢?这很有效,也很简单。(添加的代码在////之间)

class Parent extends Component {
  ///// 
  getAlert = () => {} // initial value for getAlert

  setGetAlertMethod = (newMethod) => {
    this.getAlert = newMethod;
  }
  /////

  render() {
    return (
      <Child setGetAlertMethod={this.setGetAlertMethod}>
        <button onClick={this.getAlert}>Click</button>
      </Child>
      );
    }
  }



class Child extends Component {
  /////
  componentDidMount() {
    this.props.setGetAlertMethod(this.getAlert);
  }
  /////

  getAlert() => {
    alert('clicked');
  }

  render() {
    return (
      <h1 ref="hello">Hello</h1>
    );
  }
}

如果你这样做只是因为你想让Child为它的父对象提供一个可重用的trait,那么你可以考虑使用render-props来代替。

这种技术实际上把结构颠倒过来了。Child现在包装了父对象,所以我将它重命名为AlertTrait。为了保持连续性,我保留了Parent这个名字,尽管它现在已经不是一个真正的Parent了。

// Use it like this:

  <AlertTrait renderComponent={Parent}/>


class AlertTrait extends Component {
  // You will need to bind this function, if it uses 'this'
  doAlert() {
    alert('clicked');
  }
  render() {
    return this.props.renderComponent({ doAlert: this.doAlert });
  }
}

class Parent extends Component {
  render() {
    return (
      <button onClick={this.props.doAlert}>Click</button>
    );
  }
}

在这种情况下,AlertTrait提供了一个或多个特征,它将这些特征作为道具传递给renderComponent道具中给定的任何组件。

Parent接收doAlert作为道具,并在需要时调用它。

(为了清晰起见,我在上面的例子中调用道具renderComponent。但在上面链接的React文档中,他们只称之为渲染。)

Trait组件可以在它的渲染函数中渲染父元素周围的东西,但它不渲染父元素内部的任何东西。实际上,如果它将另一个道具(例如renderChild)传递给父对象,父对象就可以在它的渲染方法中使用它,它就可以在父对象内部渲染东西。

这与OP要求的有些不同,但有些人可能会在这里结束(就像我们所做的那样),因为他们想要创建一个可重用的trait,并且认为子组件是实现这一点的好方法。

从父函数触发子函数的另一种方法是在子组件中使用componentDidUpdate函数。我将一个道具triggerChildFunc从父对象传递给子对象,初始值为null。当单击按钮时,该值更改为一个函数,Child注意到componentDidUpdate中的更改并调用自己的内部函数。

因为道具triggerChildFunc变成了一个函数,我们也得到了一个回调到父类的函数。如果Parent不需要知道函数何时被调用,则triggerChildFunc值可以从null改为true。

const { Component } = React; const { render } = ReactDOM; class Parent extends Component { state = { triggerFunc: null } render() { return ( <div> <Child triggerChildFunc={this.state.triggerFunc} /> <button onClick={() => { this.setState({ triggerFunc: () => alert('Callback in parent')}) }}>Click </button> </div> ); } } class Child extends Component { componentDidUpdate(prevProps) { if (this.props.triggerChildFunc !== prevProps.triggerChildFunc) { this.onParentTrigger(); } } onParentTrigger() { alert('parent triggered me'); // Let's call the passed variable from parent if it's a function if (this.props.triggerChildFunc && {}.toString.call(this.props.triggerChildFunc) === '[object Function]') { this.props.triggerChildFunc(); } } render() { return ( <h1>Hello</h1> ); } } render( <Parent />, document.getElementById('app') ); <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script> <div id='app'></div>

CodePen: https://codepen.io/calsal/pen/NWPxbJv?editors=1010

逻辑很简单。

在父类中使用child或ref创建一个函数。

我更喜欢父用子的创建功能。有很多种方法。

使用功能组件时

在父

function Parent(){
  const [functionToCall, createFunctionToCall] = useState(()=>()=>{})

  return (
   <Child createFunctionToCall={createFunctionToCall} />
  )
}

在儿童

function Child({createFunctionToCall}){
  useEffect(()=>{
    function theFunctionToCall(){
      // do something like setting something
      // don't forget to set dependancies properly.
    }
    createFunctionToCall(()=>theFunctionToCall)
  },[createFunctionToCall])
}