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

Sou*_*osh 0 javascript reactjs material-ui

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

父组件:

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>  
        );
    }
}
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,父组件在单击按钮时呈现子组件模式对话框(基于 Material-UI)。“保存”按钮是Dialog父组件中组件的一部分,单击时应调用Child组件中的保存函数。如您所见,我handleSaveDialog通过Child名为 的组件 props传递了一个回调函数handleSaveDatahandleSaveClick一旦子组件安装并将回调传递给父组件,单击“保存”按钮将调用子组件。

子组件:

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>      

        );
    }
}
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,我使用访问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

Yas*_*shi 5

它不会工作,因为如果你控制台登录this.handleSaveClick功能render,它将是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>
    );
  }
Run Code Online (Sandbox Code Playgroud)
class Child extends Component {

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

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

  render() {
    return <div>//..</div>;
  }
}
Run Code Online (Sandbox Code Playgroud)
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>
    );
  }
}
Run Code Online (Sandbox Code Playgroud)
class Child extends Component {
  handleSaveClick = () => {
    console.log("save clicked");
  };

  render() {
    return <div>//..</div>;
  }
}
Run Code Online (Sandbox Code Playgroud)
  • 使用回调来保存实例并使用箭头函数:
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>
    );
  }
}
Run Code Online (Sandbox Code Playgroud)
class Child extends Component {
  componentDidMount() {
    console.log("mount");
    this.props.handleSaveData(this.handleSaveClick);
  }

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

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

Run Code Online (Sandbox Code Playgroud)

您将需要使用箭头函数,onClick因为每次我们单击时它都会创建一个新函数,从而获得 的新实例handleClick。如果你通过了,this.handleClick它就不起作用,因为它是undefinedthis.handleClick您可以通过记录函数中的值来检查这一点render


注:使用该2选项更可靠。

希望这可以帮助!