我有两个组成部分:

父组件 子组件

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

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

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


当前回答

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

如何实施?

子函数返回一个函数。 子函数返回JSON:{函数、HTML或其他值}作为示例。

在这个例子中,应用这个逻辑没有意义,但很容易看出:

const {useState} = React; //Parent const Parent = () => { //custome hook const child = useChild(); return ( <div> {child.display} <button onClick={child.alert}> Parent call child </button> {child.btn} </div> ); }; //Child const useChild = () => { const [clickCount, setClick] = React.useState(0); {/* child button*/} const btn = ( <button onClick={() => { setClick(clickCount + 1); }} > Click me </button> ); return { btn: btn, //function called from parent alert: () => { 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>

其他回答

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

为了能够多次发送相同的请求,重置机制是必要的。

在父组件中

在父类的渲染方法中:

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

在子组件中

子进程更新其内部状态,复制来自道具的请求。

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

如果你这样做只是因为你想让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

父组件

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

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

父组件

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;