问题
在用React开发项目的过程中,遇到一个问题,使用connect
连接低阶组件包装成高阶组件HOC
后,父组件通通过ref
调用子组件方法时,提示xxxRef.current
为null
的错误。同时控制台Console报以下警告:
Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?
代码如下:
// 子组件
// 通过connect方式连接为高阶组件
export default connect(
mapStateToProps,
)(ComboSelectorForm);
// 父组件
constructor(props: IComboSelectorListProps | Readonly<IComboSelectorListProps>) {
super(props);
// ...
this.formRef = React.createRef();
// ...
}
// 组件挂载在formRef上
<ComboSelectorForm
ref={this.formRef}
id={this.state.id}
onSaveSuccess={this.handleSaveSuccess}
>
</ComboSelectorForm>
// 调用子组件方法
this.formRef.current.methodName();
父组件调用子组件方法后,报以下错误
TypeError: Cannot read properties of null (reading 'methodName')
解析
React的高阶组件HOC
,可以理解成在低阶组件上进行一些封装。高阶组件HOC
如果不做一些特殊处理,是无法直接访问低阶组件实例的,要想通过ref访问低阶组件实例,调用connect
时,需要传递参数{forwardRef : true}
。
connect
方法有四个参数,官方文档是这样说明的:
mapStateToProps?: Function
mapDispatchToProps?: Function | Object
mergeProps?: Function
options?: Object
对于前面三个参数先不展开来讲解,主要第四个options
参数,有以下几个属性:
{
context?: Object,
pure?: boolean,
areStatesEqual?: Function,
areOwnPropsEqual?: Function,
areStatePropsEqual?: Function,
areMergedPropsEqual?: Function,
forwardRef?: boolean,
}
其中最后一个参数forwardRef
正是我们的主角,官方文档里这样解释:
If
{forwardRef : true}
has been passed toconnect
, adding a ref to the connected wrapper component will actually return the instance of the wrapped component.
当该参数forwardRef
设置为true
时,包裹组件(wrapper component )的ref属性将会实际返回被包裹组件(wrapped component)实例。OS:原谅我翻译水平有限。(>_<)
最终解决方案
直接上代码:
// 子组件
// 通过connect方式连接为高阶组件
export default connect(
mapStateToProps,
null, // 新加参数
null, // 新加参数
{ forwardRef: true } // 新加参数
)(ComboSelectorForm);
// 父组件,与之前代码一致
constructor(props: IComboSelectorListProps | Readonly<IComboSelectorListProps>) {
super(props);
// ...
this.formRef = React.createRef();
// ...
}
// 组件挂载在formRef上
<ComboSelectorForm
ref={this.formRef}
id={this.state.id}
onSaveSuccess={this.handleSaveSuccess}
>
</ComboSelectorForm>
// 调用子组件方法
this.formRef.current.methodName();
通过以上改造后,父组件能够正常访问ref实例。😄
扩展阅读:
React + Antd实现动态切换主题功能
React + Antd实现动态切换主题功能之二(默认主题与暗黑色主题切换)
React + Router + Antd实现多标签页功能(具体代码实现)