Uncaught Invariant Violation:
You must pass a component to the function returned by connect.Instead received {}
这几天在项目中遇到,ref 转发 + connect 配合使用的场景。
开始先用 React.forwardRef api 实现了 ref 的转发,后台发现该组件也需要拿到redux里面的数据。那好,直接将被 React.forwardRef 包装的返回值(暂且这样表达),结果报错了、
报错信息如上,错误代码如下。
const Example = React.forwardRef((props) => {
return (
<div>
Example
</div>
);
})
export default connect(({ example }) => {
return { example: example.example }
})(Example);
在掘金上查了下,按照这位大大提出的方案解决了。感谢分享!
记-react-connect中使用forwardRef 问题。
正确代码:
const Example = (props) => {
return (
<div ref={props.refInstance}>Example</div>
);
}
const Component = connect(({ example }) => {
return { example: example.example }
})(Example);
export default React.forwardRef((props, ref) => <Component {...props} refInstance={ref} />)
到这里,前面的问题是解决了。解决方法是先用connect链接Redux,然后再进行 ref 转发。
懒癌发作,想着能不能不去修改之前的顺序。即:先转发,后链接Redux。
经过剖析源码,得出以下结论
- forwardRef 返回值是 虚拟dom 节点,connect()(WrappedComponent)中,WrappedComponent 是一个渲染函数, 传递 forwardRef 的返回值给connect会报错。
- connect 第四个参数 options 中的 forwardRef,当为true的时候,connect内部会做ref转发(ref透传), 当为 false/缺省 时,则不进行转发。需要 ref 转发的原因: 使用connect包装后的 UI 组件,直接暴露出去的是包装后的高阶组件,并不是 UI 组件本身。 所以 ref 链接的是 包装后的高阶组件,ref 要链接到 UI 组件本身就需要转发。
React.forwardRef 的返回值是一个对象,render 是 UI组件。参考:React.forwardRef
介于此结构,在 React.forwardRef后追加render 是可以正常运行的,实际上就是给connect传递了一个 UI组件。
const Example = React.forwardRef((props) => {
return <div>Example</div>
}).render // 直接拿到render属性,即是函数组件
export default connect(({ example }) => {
return { example: example.example }
})(Example);
这里的 WrappedComponent 即是上图中的 render props,会判断WrappedComponent是不是有效的类型(虚拟dom?个人猜测,暂时没有深究)
WrappedComponent 是 UI组件(函数组件),而React.forwardRef返回是一个对象。显然就不对,可以看到上图的错误信息与文章开头的错误信息匹配。
下图的 forwardRef 变量,即是 connect 第四个参数 options 中的 forwardRef。结合上图,可以看到 reactReduxForwardedRef 被转发到了 我们 UI组件。所以,这里可以看到 connect 第四个参数 options 中的 forwardRef 只是控制 ref 是否在connect 内部转发,并不会影响到和React.forwardRef的配合使用
参考: