ForwardRef + Redux + connect 配合使用说明

2,660 阅读2分钟
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的配合使用

参考:

ReactReact-Reduxhoist-non-react-staticsredux