This warning occurs when you try to attach a ref directly to a functional component. Unlike class components, function components don't have instances, so React cannot attach refs to them without using forwardRef.
This warning appears when you attempt to pass a ref prop directly to a functional component. In React, refs are used to access DOM elements or component instances directly, but functional components are stateless and don't have instances like class components do. When you write `<MyFunctionComponent ref={myRef} />`, React doesn't know what to attach the ref to because functional components are just functions that return JSX - they don't create component instances. This is fundamentally different from class components, which create instances with lifecycle methods and state. The warning is React's way of preventing runtime errors where you might try to access `myRef.current` and expect a component instance, but instead get `null` or `undefined`.
The primary solution is to wrap your functional component with React.forwardRef. This allows the component to receive refs and forward them to child elements:
import React, { forwardRef } from 'react';
// Before - causes warning
const MyInput = (props) => {
return <input {...props} />;
};
// After - properly forwards ref
const MyInput = forwardRef((props, ref) => {
return <input ref={ref} {...props} />;
});
// Usage in parent component
function ParentComponent() {
const inputRef = useRef(null);
const focusInput = () => {
inputRef.current?.focus();
};
return (
<>
<MyInput ref={inputRef} />
<button onClick={focusInput}>Focus Input</button>
</>
);
}The forwardRef function takes a render function that receives props and ref as separate parameters, allowing you to forward the ref to the appropriate DOM element.
If you don't need to use the reserved ref prop, you can pass a custom prop name and handle it manually:
// Child component accepts inputRef prop instead of ref
function MyInput({ inputRef, ...props }) {
return <input ref={inputRef} {...props} />;
}
// Parent component passes inputRef
function ParentComponent() {
const inputRef = useRef(null);
return <MyInput inputRef={inputRef} placeholder="Enter text" />;
}This approach works well for internal components where you control both the parent and child, but it's not compatible with libraries that expect the standard ref prop.
When you need to expose specific methods or properties rather than the entire DOM element, combine forwardRef with useImperativeHandle:
import React, { forwardRef, useRef, useImperativeHandle } from 'react';
const CustomInput = forwardRef((props, ref) => {
const inputRef = useRef(null);
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current?.focus();
},
clear: () => {
if (inputRef.current) {
inputRef.current.value = '';
}
},
getValue: () => {
return inputRef.current?.value || '';
}
}));
return <input ref={inputRef} {...props} />;
});
// Usage
function ParentComponent() {
const customInputRef = useRef(null);
const handleAction = () => {
customInputRef.current?.focus();
console.log(customInputRef.current?.getValue());
customInputRef.current?.clear();
};
return (
<>
<CustomInput ref={customInputRef} />
<button onClick={handleAction}>Interact</button>
</>
);
}This approach provides better encapsulation by only exposing the methods you explicitly define.
When working with third-party components that don't support ref forwarding, wrap them in a container element:
import ThirdPartyComponent from 'some-library';
function ParentComponent() {
const containerRef = useRef(null);
return (
<div ref={containerRef}>
<ThirdPartyComponent />
</div>
);
}The ref will attach to the div instead of the functional component, giving you access to the container's DOM node. Note that you won't have direct access to the third-party component's internal elements.
React 19 Changes: As of React 19, forwardRef is being deprecated for function components in favor of a simpler approach where function components can directly receive ref as a prop alongside other props. This change simplifies the API, but for React 18 and earlier, forwardRef remains the standard solution.
TypeScript Considerations: When using TypeScript with forwardRef, you need to properly type both the props and the ref:
type InputProps = {
placeholder?: string;
className?: string;
};
const MyInput = forwardRef<HTMLInputElement, InputProps>(
(props, ref) => {
return <input ref={ref} {...props} />;
}
);The first type parameter is the ref type, and the second is the props type.
Ref Callback Alternative: Instead of using useRef, you can use callback refs which work with both class and functional components:
function ParentComponent() {
const setInputRef = (element) => {
if (element) {
element.focus();
}
};
return <input ref={setInputRef} />;
}Performance Note: forwardRef creates a new component type, which can affect React DevTools display names. Use the displayName property to improve debugging:
const MyInput = forwardRef((props, ref) => {
return <input ref={ref} {...props} />;
});
MyInput.displayName = 'MyInput';React.FC expects children prop to be defined
React.FC no longer includes implicit children prop
Warning: You provided a `selected` prop to a form field without an `onChange` handler
You provided a 'selected' prop without an onChange handler
Failed to load source map from suspense chunk
How to fix "Failed to load source map from suspense chunk" in React
Prop spreading could cause security issues
Prop spreading could cause security issues
React Hook useCallback has a missing dependency: 'variable'. Either include it or remove the dependency array react-hooks/exhaustive-deps
React Hook useCallback has a missing dependency