This error occurs when the second argument passed to the useImperativeHandle Hook is not a function that returns the handle object. The Hook expects a function that creates and returns the custom ref handle to expose to parent components. Understanding the correct syntax and common mistakes helps you fix this React hook usage error.
The useImperativeHandle Hook allows a child component to customize the instance value that is exposed to its parent component when using ref. The second parameter must be a function (often called the "createHandle" function) that returns the object containing the methods you want to expose. If you pass something other than a function, or a function that doesn't return the expected handle, React will throw this error. This is a runtime validation error that occurs during component rendering when React detects incorrect usage of the hook.
Ensure the second argument to useImperativeHandle is a function, not an object. Instead of useImperativeHandle(ref, { focus() {...} }), use useImperativeHandle(ref, () => ({ focus() {...} })). The function should take no arguments and return the handle object.
// WRONG - passing object directly
useImperativeHandle(ref, {
focus() {
inputRef.current.focus();
}
});
// CORRECT - function that returns object
useImperativeHandle(ref, () => ({
focus() {
inputRef.current.focus();
}
}));The function must return an object containing the methods you want to expose. Make sure you're not returning undefined or forgetting the return statement. Use explicit return or implicit return with parentheses.
// WRONG - no return statement
useImperativeHandle(ref, () => {
// Missing return!
{
focus() { inputRef.current.focus(); }
}
});
// CORRECT - explicit return
useImperativeHandle(ref, () => {
return {
focus() { inputRef.current.focus(); }
};
});
// ALSO CORRECT - implicit return with parentheses
useImperativeHandle(ref, () => ({
focus() { inputRef.current.focus(); }
}));If you provide a third argument (dependencies array), ensure all reactive values used inside the createHandle function are included. Missing dependencies can cause the function to behave unexpectedly. The dependencies array is optional but recommended when your function uses props or state.
// With dependencies
useImperativeHandle(ref, () => ({
scrollTo(value) {
scrollRef.current.scrollTop = value;
}
}), [scrollRef]); // Include scrollRef if it changes
// Without dependencies (empty array)
useImperativeHandle(ref, () => ({
focus() {
inputRef.current.focus();
}
}), []); // Empty array means function never recreatesCreate a minimal component to isolate the issue:
import { useRef, useImperativeHandle, forwardRef } from 'react';
const MyInput = forwardRef(function MyInput(props, ref) {
const inputRef = useRef(null);
useImperativeHandle(ref, () => ({
focus() {
inputRef.current.focus();
console.log('focus called');
},
clear() {
inputRef.current.value = '';
}
}), []);
return <input ref={inputRef} />;
});
// Usage in parent component
function Parent() {
const inputRef = useRef(null);
const handleClick = () => {
inputRef.current?.focus();
};
return (
<div>
<MyInput ref={inputRef} />
<button onClick={handleClick}>Focus input</button>
</div>
);
}This confirms the basic pattern works, then gradually add back your logic.
In React 18 and earlier, components need to be wrapped with forwardRef to receive the ref prop. In React 19+, ref is available as a regular prop. Make sure your component structure is correct.
// React 18 and earlier
import { forwardRef, useImperativeHandle } from 'react';
const MyComponent = forwardRef((props, ref) => {
useImperativeHandle(ref, () => ({
// handle methods
}));
return <div>...</div>;
});
// React 19+
function MyComponent({ ref }) {
useImperativeHandle(ref, () => ({
// handle methods
}));
return <div>...</div>;
}In React 19, ref is available as a prop directly. In React 18 and earlier, you need to wrap your component with forwardRef to receive the ref prop. The useImperativeHandle Hook is typically used with forwardRef to customize what parent components can access via ref. Remember that overusing imperative handles can make your components harder to reason about; prefer declarative props when possible. The createHandle function should be pure and not have side effects. If you need to access current props or state inside the createHandle function, include them in the dependencies array. For complex scenarios where the exposed methods change based on props, consider using useCallback to memoize the createHandle function.
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
Cannot use private fields in class components without TS support
Cannot use private fields in class components without TS support
Cannot destructure property 'xxx' of 'undefined'
Cannot destructure property of undefined when accessing props
useNavigate() may be used only in the context of a <Router> component.
useNavigate() may be used only in the context of a Router component
Cannot find module or its corresponding type declarations
How to fix "Cannot find module or type declarations" in Vite