React组件引用问题:传递的子组件ref返回undefined如何解决?
你遇到的this.form返回undefined的核心原因是:React不会将ref作为普通props传递,而且你把带有ref的<UserForm>作为props传给<EditModal>时,这个ref的回调函数并不会被执行。因为<UserForm>的实际渲染是在<EditModal>组件内部完成的,父组件Test无法直接通过这种跨组件的方式捕获到它的实例引用。
简单来说,你在Test里给<UserForm>加的ref,就像是在“预订”一个引用,但这个元素并没有在Test的渲染树里被挂载,而是被当作一个参数传给了<EditModal>,React不会触发这个ref回调。
下面提供两种常用的解决方案,根据你的组件结构选择即可:
方法1:通过EditModal传递ref(推荐)
修改EditModal组件,让它接收一个专门的formRef prop,然后将这个ref绑定到内部渲染的UserForm上。这样父组件Test就能通过这个ref获取到UserForm的实例。
步骤1:修改EditModal组件
class EditModal extends React.Component { render() { // 解构出传入的组件和ref const { form: UserFormComponent, formRef } = this.props; return ( <div className="modal"> {/* 将formRef绑定到UserForm上 */} <UserFormComponent ref={formRef} /> </div> ); } }
步骤2:修改Test组件
class Test extends React.Component { constructor(props) { super(props); // 创建ref存储UserForm实例 this.formRef = React.createRef(); } test() { // 通过current访问UserForm实例 this.formRef.current.someMethod(); } render() { return ( <div> <EditModal form={UserForm} // 传递formRef给EditModal formRef={this.formRef} ref={(edit) => { this.edit = edit; }} /> </div> ); } }
方法2:使用回调ref传递
如果你不想用createRef,也可以通过回调函数的方式传递ref:
步骤1:修改EditModal组件
class EditModal extends React.Component { render() { const { form: UserFormComponent, setFormRef } = this.props; return ( <div className="modal"> {/* 将回调函数作为ref传给UserForm */} <UserFormComponent ref={setFormRef} /> </div> ); } }
步骤2:修改Test组件
class Test extends React.Component { test() { this.form.someMethod(); } render() { return ( <div> <EditModal form={UserForm} // 传递回调函数获取UserForm的ref setFormRef={(form) => { this.form = form; }} ref={(edit) => { this.edit = edit; }} /> </div> ); } }
当你写<EditModal form={<UserForm ref={(form) => { this.form = form; }} />} />时,<UserForm>只是一个描述组件结构的React元素对象,不是实际挂载的组件实例。只有当这个元素被React渲染到DOM中时,ref回调才会执行。但React会把ref当作特殊属性处理,不会将其包含在props中传递给子组件,再加上<UserForm>的渲染控制权在EditModal手里,原写法的ref回调永远不会触发,所以this.form一直是undefined。
内容的提问来源于stack exchange,提问作者kostik

