When wrapping a forwardRef component with Redux connect(), refs fail to pass through correctly. This happens because connect() needs explicit configuration to handle ref forwarding through its higher-order component wrapper.
Fixes forwardRef cannot be used with connect() from react-redux
import React from 'react';
import { connect } from 'react-redux';
const MyComponent = React.forwardRef((props, ref) => {
return (
<div ref={ref}>
<h1>{props.title}</h1>
{/* component content */}
</div>
);
});
const mapStateToProps = (state) => ({
title: state.title,
});
// Add { forwardRef: true } as the fourth argument
export default connect(
mapStateToProps,
null,
null,
{ forwardRef: true }
)(MyComponent);import React from 'react';import { connect } from 'react-redux';const MyComponent = React.forwardRef((props, ref) => {return (<div ref={ref}><h1>{props.title}</h1>{/* component content */}</div>);});const mapStateToProps = (state) => ({title: state.title,});// Add { forwardRef: true } as the fourth argumentexport default connect(mapStateToProps,null,null,{ forwardRef: true })(MyComponent);forwardRef cannot be used with connect() from react-redux
This error occurs when you try to use React.forwardRef() on a component that's wrapped with Redux's connect() function without proper configuration. The connect() higher-order component (HOC) creates a wrapper around your component, which intercepts the ref by default. In React-Redux v6 and later, the library changed how refs are handled - replacing the deprecated withRef option with forwardRef. When you compose connect with forwardRef incorrectly, React sees the forwardRef result (which is an object) being passed where it expects a function component, causing type errors. Additionally, the ref doesn't reach your intended component because connect() intercepts it at the wrapper level. This is a common migration issue when upgrading from React-Redux v5 (which used withRef and getWrappedInstance) to v6+ (which uses the forwardRef option). The problem affects any component that needs direct DOM access or imperative methods exposed through refs.
The primary solution is to pass { forwardRef: true } as the fourth argument to connect():
import React from 'react';
import { connect } from 'react-redux';
const MyComponent = React.forwardRef((props, ref) => {
return (
<div ref={ref}>
<h1>{props.title}</h1>
{/* component content */}
</div>
);
});
const mapStateToProps = (state) => ({
title: state.title,
});
// Add { forwardRef: true } as the fourth argument
export default connect(
mapStateToProps,
null,
null,
{ forwardRef: true }
)(MyComponent);Now the ref will be passed through to your component correctly.
With forwardRef enabled, you can now use refs normally in parent components:
import React, { useRef, useEffect } from 'react';
import MyConnectedComponent from './MyConnectedComponent';
function ParentComponent() {
const componentRef = useRef(null);
useEffect(() => {
if (componentRef.current) {
// Access the DOM element or component instance
console.log(componentRef.current);
componentRef.current.focus(); // if it's a focusable element
}
}, []);
return <MyConnectedComponent ref={componentRef} />;
}The ref now points to the actual wrapped component, not the connect() wrapper.
If you need to forward the ref to a specific inner element rather than the component root, wrap the connected component with forwardRef:
import React from 'react';
import { connect } from 'react-redux';
// Define component without forwardRef
const MyComponent = ({ title, innerRef }) => {
return (
<div>
<input ref={innerRef} type="text" />
<h1>{title}</h1>
</div>
);
};
const mapStateToProps = (state) => ({
title: state.title,
});
// Connect first, then wrap with forwardRef
const ConnectedComponent = connect(mapStateToProps)(MyComponent);
export default React.forwardRef((props, ref) => (
<ConnectedComponent {...props} innerRef={ref} />
));This pattern gives you more control over where the ref is forwarded.
If you're upgrading from React-Redux v5, replace the old withRef pattern:
Old pattern (v5):
export default connect(
mapStateToProps,
null,
null,
{ withRef: true }
)(MyComponent);
// In parent:
myComponentRef.current.getWrappedInstance().someMethod();New pattern (v6+):
export default connect(
mapStateToProps,
null,
null,
{ forwardRef: true }
)(MyComponent);
// In parent - direct access, no getWrappedInstance
myComponentRef.current.someMethod();The getWrappedInstance() call is no longer needed with the forwardRef option.
Ensure you're using the correct connect() signature with all four parameters:
connect(
mapStateToProps, // 1st: map state to props
mapDispatchToProps, // 2nd: map dispatch to props (or null)
mergeProps, // 3rd: merge function (or null)
{
forwardRef: true, // 4th: options object
// other options...
}
)(Component)If you're only using mapStateToProps, you still need to pass null for the 2nd and 3rd parameters:
connect(mapStateToProps, null, null, { forwardRef: true })(Component)TypeScript considerations: When using forwardRef with connect() in TypeScript, you may need to explicitly type your ref:
interface MyComponentProps {
title: string;
}
const MyComponent = React.forwardRef<HTMLDivElement, MyComponentProps>(
(props, ref) => {
return <div ref={ref}>{props.title}</div>;
}
);Performance note: The forwardRef option has minimal performance impact. The connect() HOC already creates a wrapper component; enabling forwardRef simply configures how refs are passed through.
React Hooks alternative: If you're building new components, consider using the useSelector and useDispatch hooks from React-Redux instead of connect(). Hooks work naturally with forwardRef:
const MyComponent = React.forwardRef((props, ref) => {
const title = useSelector(state => state.title);
const dispatch = useDispatch();
return <div ref={ref}>{title}</div>;
});This eliminates the connect() HOC entirely and provides cleaner ref forwarding.
Multiple refs: If you need to forward multiple refs or combine refs, use the useImperativeHandle hook:
const MyComponent = React.forwardRef((props, ref) => {
const localRef = useRef(null);
useImperativeHandle(ref, () => ({
focus: () => localRef.current?.focus(),
getValue: () => localRef.current?.value,
}));
return <input ref={localRef} />;
});Legacy codebase migration: When migrating large codebases from React-Redux v5 to v6+, search for all instances of "withRef: true" and "getWrappedInstance()" to identify components that need updating to the forwardRef pattern.