从父方法调用子方法

我有两个组成部分:

  1. 父组件
  2. 儿童部分

我试图从父调用孩子的方法,我尝试了这种方式,但不能得到一个结果:

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

有没有一种方法可以从父级调用孩子的方法?

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

711191 次浏览

首先,让我表达一下,这通常是React领域的第一种方式。通常你想做的是在道具中将功能传递给孩子们,并在事件中传递孩子们的通知(或者更好的是:dispatch)。

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

以前,ref仅支持基于类的组件。随着ReactHooks的出现,情况不再是这样

现代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 argumentuseImperativeHandle(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 oneconst 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>

回调引用接口

Callback风格的ref是实现这一目标的另一种方法,尽管在现代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更多答案参考这里在React子组件上调用方法

通过查看“原因”组件的ref,你打破了封装,如果不仔细检查它使用的所有地方,就不可能重构该组件。因此,我们强烈建议将ref视为组件的私有,就像状态一样。

一般来说,数据应该通过props沿着树传递。这有一些例外(例如调用. Focus()或触发一个不会真正“改变”状态的一次性动画),但任何时候你公开一个名为“set”的方法时,props通常是更好的选择。试着让它让内部输入组件担心它的大小和外观,这样它的祖先就不会担心它了。

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

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()黑客。

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

如果你这样做只是因为你想让孩子为父母提供一个可重用的特征,那么你可以考虑这样做使用渲染道具

该技术实际上颠倒了结构。Child现在包装了父级,所以我在下面将其重命名为AlertTrait。我保留了名称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 prop中给出的任何组件。

父节点接收doAlert作为prop,并且可以在需要时调用它。

(为了清楚起见,我在上面的例子中调用了proprenderComponent。但在上面链接的React文档中,他们只是称之为render。)

Trait组件可以在它的渲染函数中渲染父级周围的东西,但它不会渲染父级内部的任何东西。实际上,如果它将另一个prop(例如renderChild)传递给父级,它可以渲染父级内部的东西,然后父级可以在其渲染方法中使用该prop。

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

我认为调用方法的最基本方法是在子组件上设置一个请求。然后,一旦子组件处理了请求,它就会调用回调方法来重置请求。

复位机制是必要的,以便能够在彼此之后多次发送相同的请求。

在父组件中

在父级的渲染方法中:

const { request } = this.state;return (<Child request={request} onRequestHandled={()->resetRequest()}/>);

父母需要两种方法,在两个方向上与孩子沟通。

sendRequest() {const request = { param: "value" };this.setState({ request });}
resetRequest() {const request = null;this.setState({ request });}

在子组件中

子进程更新其内部状态,从props复制请求。

constructor(props) {super(props);const { request } = props;this.state = { request };}
static getDerivedStateFromProps(props, state) {const { request } = props;if (request !== state.request ) return { request };return null;}

最后它处理请求,并将重置发送给父级:

componentDidMount() {const { request } = this.state;// todo handle request.
const { onRequestHandled } = this.props;if (onRequestHandled != null) onRequestHandled();}

我们可以用另一种方式使用ref

我们将创建一个父元素,它将渲染一个<Child/>组件。如您所见,将要渲染的组件,您需要添加参考属性并为其提供名称。
然后,位于父类中的triggerChildAlert函数将访问this上下文的refs属性(当triggerChildAlert函数被触发时将访问子引用,并且它将具有子元素的所有函数)。

class Parent extends React.Component {triggerChildAlert(){this.refs.child.callChildMethod();// to get child parent returned  value-// this.value = this.refs.child.callChildMethod();// alert('Returned value- '+this.value);}
render() {return (<div>{/* Note that you need to give a value to the ref parameter, in this case child*/}<Child ref="child" /><button onClick={this.triggerChildAlert}>Click</button></div>);}}

现在,子组件,如之前理论上设计的,将如下所示:

class Child extends React.Component {callChildMethod() {alert('Hello World');// to return some value// return this.state.someValue;}
render() {return (<h1>Hello</h1>);}}

这里是源代码-
希望能帮到你!

你可以很容易地达到这个目的

步骤-

  1. 在父类的状态中创建一个布尔变量。当您想调用函数时更新它。
  2. 创建一个prop变量并分配布尔变量。
  3. 从子组件使用props访问该变量并通过if条件执行您想要的方法。

    class Child extends Component {Method=()=>{--Your method body--}render() {return (//check whether the variable has been updated or notif(this.props.updateMethod){this.Method();})}}
    class Parent extends Component {
    constructor(){this.state={callMethod:false}
    }render() {return (
    //update state according to your requirementthis.setState({callMethod:true}}<Child updateMethod={this.state.callMethod}></Child>);}}

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

由于proptriggerChildFunc改变了一个函数,我们也得到一个对父函数的回调。如果父函数不需要知道什么时候调用函数,那么值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 functionif (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>

代码页:https://codepen.io/calsal/pen/NWPxbJv?editors=1010

我正在使用useEffect钩子来克服做这一切的头痛,所以现在我将一个变量传递给孩子,如下所示:

import { useEffect, useState } from "react";
export const ParentComponent = () => {const [trigger, setTrigger] = useState(false);
return (<div onClick={() => { setTrigger(trigger => !trigger); }}><ChildComponent trigger={trigger}></ChildComponent></div>);};
export const ChildComponent = (props) => {const triggerInvokedFromParent = () => {console.log('TriggerInvokedFromParent');};
useEffect(() => {triggerInvokedFromParent();}, [props.trigger]);
return <span>ChildComponent</span>;};

这是我的演示:https://stackblitz.com/edit/react-dgz1ee?file=styles.css

我正在使用useEffect来调用子组件的方法。我已经尝试过Proxy and Setter_Getter,但or远useEffect似乎是从父组件调用子方法的更方便的方法。要使用Proxy and Setter_Getter,似乎首先要克服一些微妙之处,因为首先渲染的元素是ref.current return => <div/>的特异性对象。关于useEffect,您还可以利用这种方法来设置父级的状态,具体取决于您想对子级做什么。

在我提供的演示链接中,你会发现我的完整ReactJS代码,里面有我的草稿,所以你可以欣赏我的解决方案的工作流程。

在这里,我只向您提供我的ReactJS片段和相关代码。

import React, {Component,createRef,forwardRef,useState,useEffect} from "react";
{...}
// Child component// I am defining here a forwardRef's element to get the Child's methods from the parent// through the ref's element.let Child = forwardRef((props, ref) => {// I am fetching the parent's method here// that allows me to connect the parent and the child's componentslet { validateChildren } = props;// I am initializing the state of the children// good if we can even leverage on the functional children's statelet initialState = {one: "hello world",two: () => {console.log("I am accessing child method from parent :].");return "child method achieve";}};// useState initializationconst [componentState, setComponentState] = useState(initialState);// useEffect will allow me to communicate with the parent// through a lifecycle data flowuseEffect(() => {ref.current = { componentState };validateChildren(ref.current.componentState.two);});
{...}
});
{...}
// Parent componentclass App extends Component {// initialize the ref inside the constructor elementconstructor(props) {super(props);this.childRef = createRef();}
// I am implementing a parent's method// in child useEffect's methodvalidateChildren = childrenMethod => {// access children method from parentchildrenMethod();// or signaling children is readyconsole.log("children active");};
{...}render(){return ({// I am referencing the children// also I am implementing the parent logic connector's function// in the child, here => this.validateChildren's function}<Child ref={this.childRef} validateChildren={this.validateChildren} /></div>)}

我们很满意我们称之为useCounterKey的自定义钩子。它只是设置了一个计数器键,或者一个从零开始计数的键。它返回的函数重置键(即增量)。(我相信这是重置组件的React中最惯用的方法-只需撞击键。)

然而,这个钩子也适用于任何你想向客户端发送一次性消息做某事的情况。例如,我们用它来将子控件集中在某个父事件上-它只是在密钥更新时自动聚焦。(如果需要更多道具,可以在重置密钥之前设置它们,以便在事件发生时可用。)

这个方法有一点学习曲线b/c,它不像典型的事件处理程序那么简单,但它似乎是我们在React中发现的最惯用的处理方法(因为键已经以这种方式运行)。

// Main helper hook:export function useCounterKey() {const [key, setKey] = useState(0);return [key, () => setKey(prev => prev + 1)] as const;}

示例用法:

// Sample 1 - normal React, just reset a control by changing Key on demandfunction Sample1() {const [inputLineCounterKey, resetInputLine] = useCounterKey();
return <><InputLine key={inputLineCounterKey} /><button onClick={() => resetInputLine()} /><>;}
// Second sample - anytime the counterKey is incremented, child calls focus() on the inputfunction Sample2() {const [amountFocusCounterKey, focusAmountInput] = useCounterKey();
// ... call focusAmountInput in some hook or event handler as needed
return <WorkoutAmountInput focusCounterKey={amountFocusCounterKey} />}
function WorkoutAmountInput(props) {useEffect(() => {if (counterKey > 0) {// Don't focus initiallyfocusAmount();}}, [counterKey]);
// ...}

(归功于肯特·多德的反键概念

使用效果的替代方法:

父:

const [refresh, doRefresh] = useState(0);<Button onClick={() => doRefresh(prev => prev + 1)} /><Children refresh={refresh} />

儿童:

useEffect(() => {performRefresh(); //children function of interest}, [props.refresh]);

这里有一个bug?要注意:我同意rossipedia的解决方案,使用的转发Ref, useRef, useImperativeHandle

网上有一些虚假信息说ref只能从React Class组件中创建,但是如果你使用上面提到的钩子,你确实可以使用Function Components。注意,钩子只有在我将文件更改为导出组件时不使用with Rout()后才对我起作用。即从

export default withRouter(TableConfig);

而是成为

export default TableConfig;

事后看来,无论如何,这样的组件都不需要With Rout(),但通常它不会伤害任何东西。我的用例是,我创建了一个组件来创建一个Table来处理配置值的查看和编辑,并且我希望能够告诉这个子组件在点击父表单的重置按钮时重置它的状态值。UseRef()无法正确获取ref或ref.current(一直为空),直到我从包含我的子组件TableConfig的文件中删除with R的()

我对这里提出的任何解决方案都不满意。实际上有一个非常简单的解决方案,可以使用纯Javascript完成,而不依赖基本props对象以外的一些React功能——它给你带来了双向通信的好处(父->子,子->父)。你需要从父组件传递一个对象给子组件。这个对象就是我所说的“双向引用”或简称biRef。基本上,该对象包含对父组件想要公开的父组件中方法的引用。子组件将方法附加到父组件可以调用的对象上。类似这样的东西:

// Parent component.function MyParentComponent(props) {
function someParentFunction() {// The child component can call this function.}
function onButtonClick() {// Call the function inside the child component.biRef.someChildFunction();}
// Add all the functions here that the child can call.var biRef = {someParentFunction: someParentFunction}
return <div><MyChildComponent biRef={biRef} /><Button onClick={onButtonClick} /></div>;}

// Child componentfunction MyChildComponent(props) {
function someChildFunction() {// The parent component can call this function.}

function onButtonClick() {// Call the parent function.props.biRef.someParentFunction();}
// Add all the child functions to props.biRef that you want the parent// to be able to call.props.biRef.someChildFunction = someChildFunction;
return <div><Button onClick={onButtonClick} /></div>;}

此解决方案的另一个优点是,您可以在父级和子级中添加更多函数,同时仅使用单个属性将它们从父级传递给子级。

对上面代码的改进是不将父函数和子函数直接添加到biRef对象中,而是添加到子成员中。父函数应该添加到名为“父”的成员中,而子函数应该添加到名为“子”的成员中。

// Parent component.function MyParentComponent(props) {
function someParentFunction() {// The child component can call this function.}
function onButtonClick() {// Call the function inside the child component.biRef.child.someChildFunction();}
// Add all the functions here that the child can call.var biRef = {parent: {someParentFunction: someParentFunction}}
return <div><MyChildComponent biRef={biRef} /><Button onClick={onButtonClick} /></div>;}

// Child componentfunction MyChildComponent(props) {
function someChildFunction() {// The parent component can call this function.}

function onButtonClick() {// Call the parent function.props.biRef.parent.someParentFunction();}
// Add all the child functions to props.biRef that you want the parent// to be able to call.props.biRef {child: {someChildFunction: someChildFunction}}
return <div><Button onClick={onButtonClick} /></div>;}

通过将父函数和子函数放在biRef对象的不同成员中,您将在两者之间有一个清晰的分离,并且很容易看到哪些属于父函数或子函数。如果两个函数中出现相同的函数,它还有助于防止子组件意外覆盖父函数。

最后一件事是,如果你注意到,父组件使用var创建biRef对象,而子组件通过props对象访问它。不在父组件中定义biRef对象并通过其自己的props参数(可能是UI元素层次结构中的情况)从其父组件访问它可能很诱人。这是有风险的,因为子组件可能认为它调用的父组件属于父组件,而实际上它可能属于祖父母。只要你意识到这一点,这没有错。除非您有理由支持父/子关系之外的某些层次结构,否则最好在父组件中创建biRef。

我希望我没有重复上面的任何内容,但是传递一个回调道具来设置父函数怎么样?这很有效并且很容易。(添加的代码在///之间)

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

你可以很容易地应用这个逻辑,使用你的子组件作为反应自定义钩子

如何实施?

  • 您的孩子返回一个函数。

  • 您的孩子返回JSON:{函数、超文本标记语言或其他值}作为示例。

In the example doesn't make sense to apply this logic but it is easy to see:

const {useState} = React;
//Parentconst Parent = () => {//custome hookconst child = useChild();
return (<div>{child.display}<button onClick={child.alert}>Parent call child</button>{child.btn}</div>);};
//Childconst useChild = () => {
const [clickCount, setClick] = React.useState(0);  
{/* child button*/}const btn = (<buttononClick={() => {setClick(clickCount + 1);}}>Click me</button>);
return {btn: btn,//function called from parentalert: () => {alert("You clicked " + clickCount + " times");},display: <h1>{clickCount}</h1>};};
const rootElement = document.getElementById("root");ReactDOM.render(<Parent />, rootElement);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script><div id="root"></div>

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

功能组件解决方案

在功能组件中,您必须使用useImperativeHandle来将ref获取到子组件中,如下所示

import React, { forwardRef, useRef, useImperativeHandle } from 'react';export default function ParentFunction() {const childRef = useRef();return (<div className="container"><div>Parent Component</div><buttononClick={() => { 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>);}}

逻辑很简单。

Create a function in parent using child or use 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])}

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

父组件

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

在这里,我将为您提供可能发生的四种可能的组合:

  1. 类父|钩子
  2. 钩父|类儿童
  3. 钩父|钩子
  4. 类父|类子

1.类父|钩子

class Parent extends React.Component {constructor(props) {super(props)this.myRef = React.createRef()}
render() {return (<View><Child ref={this.myRef}/><Button title={'call me'}onPress={() => this.myRef.current.childMethod()}/></View>)}}
const Child = React.forwardRef((props, ref) => {
useImperativeHandle(ref, () => ({childMethod() {childMethod()}}))
function childMethod() {console.log('call me')}
return (<View><Text> I am a child</Text></View>)})

2.钩子父|类子

function Parent(props) {
const myRef = useRef()
return (<View><Child ref={myRef}/><Button title={'call me'}onPress={() => myRef.current.childMethod()}/></View>)}
class Child extends React.Component {
childMethod() {console.log('call me')}
render() {return (<View><Text> I am a child</Text></View>)}}

3.钩父|钩子

function Parent(props) {
const myRef = useRef()
return (<View><Child ref={myRef}/><Button title={'call me'}onPress={() => myRef.current.childMethod()}/></View>)}
const Child = React.forwardRef((props, ref) => {
useImperativeHandle(ref, () => ({childMethod() {childMethod()}}))
function childMethod() {console.log('call me')}
return (<View><Text> I am a child</Text></View>)})

4.班级家长|班级孩子

class Parent extends React.Component {constructor(props) {super(props)this.myRef = React.createRef()}
render() {return (<View><Child ref={this.myRef}/><Button title={'call me'}onPress={() => this.myRef.current.childMethod()}/></View>)}}
class Child extends React.Component {
childMethod() {console.log('call me')}
render() {return (<View><Text> I am a child</Text></View>)}}

父组件

import Child from './Child'
export default function Parent(props) {const [childRefreshFunction, setChildRefreshFunction] = useState(null);
return (<div><button type="button" onClick={() => {childRefreshFunction();}}>Refresh child</button><Child setRefreshFunction={(f) => {setChildRefreshFunction(f);}} /></div>)}

儿童部分

export default function Child(props) {
useEffect(() => {props.setRefreshFunction(() => refreshMe);}, []);
function refreshMe() {fetch('http://example.com/data.json')....};
return (<div>child</div>)}

此模式类似于@brickingup回答。但在这个版本中,您可以设置任意数量的子操作。

import { useEffect } from "react";
export const Parent = () => {const childEvents = { click: () => {} };
return (<div onClick={() => childEvents.click()}><Child events={childEvents}></Child></div>);};
export const Child = (props) => {const click = () => {alert("click from child");};
useEffect(() => {if (props.events) {props.events.click = click;}}, []);
return <span>Child Component</span>;};

我尝试使用createRefuseRef。不知何故,它们都返回null

其次,这个答案建议传递一个prop,它设置了一个function,这在我看来是最合理的。但是如果你的子组件在多个地方使用,你应该将额外的prop添加到其他地方。此外,如果你想在孙子中调用一个方法,这个方法可能太冗长或口齿不清。

所以我用一种非常原始的方式制作了自己的函数存储。

下面是functionStore.js文件

const fns = {};
export function setFn(componentName, fnName, fn) {if (fns[componentName]) {fns[componentName][fnName] = fn;} else {fns[componentName] = { fnName: fn };}}
export function callFn(componentName, fnName) {fns[componentName][fnName]();}

我只是设置需要从任何组件调用的函数。

import { setFn } from "./functionStore";export class AComponent extends React.Component {componentDidMount() {setFn("AComponent", "aFunc", this.aFunc);}aFunc = () => { console.log("aFunc is called!"); };}

那我就从其他部件调用它

import { callFn } from "./functionStore";export class BComponent extends React.Component {  
// just call the functionbFunc = () => {callFn("AComponent", "aFunc");};}

一个缺点是要调用的函数应该是无参数的。但这也可能是固定的。目前,我不需要传递参数。