繁体   English   中英

在React.js中从父组件调用子组件函数

[英]Calling Child component function from Parent component in React.js

我试图从父组件中的按钮单击事件中调用子组件中的函数。

父组件:

class Parent extends Component{
    constructor(props){
        super(props);
        this.state = {
            //..
        }
    }

    handleSaveDialog = (handleSaveClick) => {
        this.handleSaveClick = handleSaveClick;
    }

    render(){
        return(
            <div>
                <Button onClick={this.openDialog}>Open Dialog</Button>
                <Dialog>
                    <DialogTitle id="form-dialog-title">Child Dialog</DialogTitle>
                    <DialogContent>
                        <Child handleSaveData={this.handleSaveDialog}/>
                    </DialogContent>
                    <DialogActions>
                        <Button onClick={this.handleSaveClick} color="primary">
                            Save
                        </Button>
                    </DialogActions>
                </Dialog>       
            </div>  
        );
    }
}

在上面的代码中,单击按钮后,父组件将呈现子组件模态对话框(基于Material-UI)。 单击“保存”按钮,即“父项”中“ Dialog组件的一部分,应在“ Child组件中调用保存功能。 正如你所看到的,我已经过了一个回调函数handleSaveDialog通过Child命名组件道具handleSaveData 一旦子组件安装并将回调传递给父组件,则单击保存按钮将在子组件上调用handleSaveClick

子组件:

class Child extends Component{
    constructor(props){
        super(props);
        this.state = {
            //..
        }
    }

    componentDidMount(){
        console.log('mount');
        this.props.handleSaveData( () => this.handleSaveClick());
    }

    handleSaveClick = () => {
        console.log('save clicked');
    }

    render(){
        return(
            <div>
                //..
            </div>      

        );
    }
}

在上面的代码中,我正在使用访问Parent组件props传递的回调函数,并将其绑定到Child组件的save fucntion handleSaveClick

问题:

当我第一次单击“父项”中的“打开对话框”按钮时,该Dialog安装“子项”组件。 但是,单击“ Save按钮不起作用(没有错误)。 关闭对话框后,当我重新打开对话框并单击“保存”时,将触发“子”对话框中的handleSaveClick ,并在浏览器控制台中记录一条消息。 知道为什么第二次而不是第一次有效吗? 请记住,仅当我单击父组件上的“打开对话框”时,才会装入/加载子组件。

参考文献:

https://material-ui.com/components/dialogs/#form-dialogs

从父级调用子级方法

https://github.com/kriasoft/react-starter-kit/issues/909#issuecomment-390556015

好吧,我不知道为什么会有这种情况,但是我想到的第一件事就是可以在Parent组件中编写handleSaveClick方法。 并且如果您需要在子组件中可能发生的任何操作上使用该函数,则可以将该函数作为父组件的prop传递。 所以你两种情况都可以处理

  • 您可以在父组件中发生的事情上调用此方法
  • 您可以对子组件中发生的任何操作使用相同的方法。

如果仍然认为您必须在子组件中定义方法,则可以使用refs

这将不起作用,因为如果您在render函数中控制台登录this.handleSaveClick ,则将无法undefined它,因为没有重新渲染。 因此,有两种方法可以实现:

class Parent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      open: false
    };
  }

  openDialog = () => {
    this.setState(preState => ({
      open: !preState.open
    }));
  };

  handleSaveDialog = handleSaveRef => {
    this.setState({
      handleSaveClick: handleSaveRef
    });
  };

  render() {
    console.log("Render", this.handleSaveClick);
    return (
      <div>
        <Button onClick={this.openDialog}>Open Dialog</Button>
        <Dialog open={this.state.open}>
          <DialogTitle id="form-dialog-title">Child Dialog</DialogTitle>
          <DialogContent>
            <Child handleSaveData={this.handleSaveDialog} />
          </DialogContent>
          <DialogActions>
            <Button onClick={this.state.handleSaveClick} color="primary">
              Save
            </Button>
          </DialogActions>
        </Dialog>
      </div>
    );
  }
class Child extends Component {

  componentDidMount() {
    console.log("mount");
    this.props.handleSaveData(this.handleSaveClick);
  }

  handleSaveClick = () => {
    console.log("save clicked");
  };

  render() {
    return <div>//..</div>;
  }
}

const childRef = React.createRef();
class Parent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      open: false
    };
  }

  openDialog = () => {
    this.setState(preState => ({
      open: !preState.open
    }));
  };

  handleSaveClick = () => {
    if (childRef.current) {
      childRef.current.handleSaveClick();
    }
  };

  render() {
    return (
      <div>
        <Button onClick={this.openDialog}>Open Dialog</Button>
        <Dialog open={this.state.open}>
          <DialogTitle id="form-dialog-title">Child Dialog</DialogTitle>
          <DialogContent>
            <Child ref={childRef} />
          </DialogContent>
          <DialogActions>
            <Button onClick={this.handleSaveClick} color="primary">
              Save
            </Button>
          </DialogActions>
        </Dialog>
      </div>
    );
  }
}
class Child extends Component {
  handleSaveClick = () => {
    console.log("save clicked");
  };

  render() {
    return <div>//..</div>;
  }
}

  • 使用回调保存实例,然后使用箭头功能:
class Parent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      open: false
    };
  }

  openDialog = () => {
    this.setState(preState => ({
      open: !preState.open
    }));
  };

  handleSaveDialog = handleSaveRef => {
    this.handleSaveClick = handleSaveRef;
  };

  render() {
    return (
      <div>
        <Button onClick={this.openDialog}>Open Dialog</Button>
        <Dialog open={this.state.open}>
          <DialogTitle id="form-dialog-title">Child Dialog</DialogTitle>
          <DialogContent>
            <Child handleSaveData={this.handleSaveDialog} />
          </DialogContent>
          <DialogActions>
            <Button onClick={() => this.handleSaveClick()} color="primary">
              Save
            </Button>
          </DialogActions>
        </Dialog>
      </div>
    );
  }
}
class Child extends Component {
  componentDidMount() {
    console.log("mount");
    this.props.handleSaveData(this.handleSaveClick);
  }

  handleSaveClick = () => {
    console.log("save clicked");
  };

  render() {
    return <div>//..</div>;
  }
}

您将需要在onClick使用箭头函数,因为每次我们单击它都会创建一个新函数,从而获得handleClick的新实例。 而且如果您通过this.handleClick它将无法使用,因为它是undefined 您可以通过在render函数中记录this.handleClick的值来进行检查。


注意:使用2选项更加可靠。

希望这可以帮助!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM