React父组件调用子组件方法后Material-UI Dialog无法关闭问题求助
问题根因
报错本质是handleClose方法的this指向丢失,调用this.setState时this为undefined。handleOpen能正常调用是因为你通过ref.current.handleOpen()执行方法时,执行上下文就是子组件实例,this指向正确;而handleClose是直接绑定在DOM元素的onClick事件上,类组件的普通方法默认不会绑定实例this,触发时this丢失就会抛出错误。
修复方案
方案1:快速修复现有代码
修正子组件的方法this绑定即可,推荐直接用箭头函数定义类方法:
class Pop_dialog extends Component { constructor(props) { super(props) this.state = { open: false } } // 用箭头函数定义方法,this自动绑定到组件实例 handleOpen = () => { console.log('A') this.setState({ open: true }) } handleClose = () => { console.log('B') this.setState({ open: false }) } // render部分代码保持不变 render() { return ( <Dialog open={this.state.open} onClose={this.handleClose} aria-labelledby="form-dialog-title"> <DialogTitle id="form-dialog-title">Subscribe</DialogTitle> <DialogContent> <DialogContentText> To subscribe to this website, please enter your email address here. We will send updates occasionally. </DialogContentText> <TextField autoFocus margin="dense" id="name" label="Email Address" type="email" fullWidth /> </DialogContent> <DialogActions> <Button onClick={this.handleClose} color="primary"> Cancel </Button> <Button onClick={this.handleClose} color="primary"> Subscribe </Button> </DialogActions> </Dialog> ) } }
方案2:更推荐的受控组件实现(复用性更强)
符合React单向数据流规范,避免使用ref调用组件实例的反模式,方便后续扩展弹窗的自定义内容、提交回调等能力:
子组件改造
移除内部的open状态,改为从props接收控制参数和回调:
class Pop_dialog extends Component { render() { // 可扩展title、content、按钮文案等props,进一步提升复用性 const { open, onClose, onSubmit } = this.props return ( <Dialog open={open} onClose={onClose} aria-labelledby="form-dialog-title"> <DialogTitle id="form-dialog-title">Subscribe</DialogTitle> <DialogContent> <DialogContentText> To subscribe to this website, please enter your email address here. We will send updates occasionally. </DialogContentText> <TextField autoFocus margin="dense" id="name" label="Email Address" type="email" fullWidth /> </DialogContent> <DialogActions> <Button onClick={onClose} color="primary"> Cancel </Button> <Button onClick={() => { onSubmit?.() onClose() }} color="primary"> Subscribe </Button> </DialogActions> </Dialog> ) } }
父组件调用
父组件自行维护弹窗显隐状态:
// 父组件constructor初始化状态 constructor(props) { super(props) this.state = { dialogOpen: false } } triggerDialog() { this.setState({ dialogOpen: true }) } handleDialogClose() { this.setState({ dialogOpen: false }) } handleDialogSubmit() { // 处理表单提交逻辑 } render () { return ( <> {/* 父组件其他渲染内容 */} <Pop_dialog open={this.state.dialogOpen} onClose={this.handleDialogClose.bind(this)} onSubmit={this.handleDialogSubmit.bind(this)} /> </> ) }
你之前尝试将open作为props传入时无法关闭,是因为没有补充对应的关闭回调通知父组件修改状态,按上述写法调整即可正常运行。
内容的提问来源于stack exchange,提问作者Alexis Mercado
相关产品推荐
相关产品推荐

