Imperative Handles
Loading "Intro to Imperative Handles"
Run locally for transcripts
Sometimes you need to expose a method to the parent component that allows the
parent to imperatively interact with the child component. This is done using
a
ref
which you get from the useRef
hook. You'll recall that the useRef
hook allows you to have an object that's associated to a particular instance of
a component which persists across renders and doesn't trigger rerenders when
it's changed.So a parent component can pass a
ref
to a child component and then the child
component can attach methods to that ref
which the parent can then call:type InputAPI = { focusInput: () => void }
function MyInput({
ref,
...props
}: React.InputHTMLAttributes<HTMLInputElement> & {
ref: React.RefObject<InputAPI>
}) {
const inputRef = useRef()
ref.current = {
focusInput: () => inputRef.current.focus(),
}
return <input ref={inputRef} {...props} />
}
function App() {
const myInputRef = useRef<InputAPI>(null)
return (
<div>
<MyInput ref={myInputRef} placeholder="Enter your name" />
<button onClick={() => myInputRef.current.focusInput()}>
Focus the input
</button>
</div>
)
}
This actually works, however there are some edge case bugs with this approach
when applied in React's concurrent/suspense features (also it doesn't support
callback refs). So instead, we'll use the
useImperativeHandle
hook to do this:type InputAPI = { focusInput: () => void }
function MyInput({
ref,
...props
}: React.InputHTMLAttributes<HTMLInputElement> & {
ref: React.RefObject<InputAPI>
}) {
const inputRef = useRef()
useImperativeHandle(
ref,
() => ({ focusInput: () => inputRef.current.focus() }),
[],
)
return <input ref={inputRef} {...props} />
}
You'll notice that empty array. That's another dependency array. We don't
include the
inputRef
in there even though it's used in the function because
you actually don't need to include refs in the dependency array. Learn more
about this in
Why you shouldn't put refs in a dependency array.useImperativeHandle
allows us to expose imperative methods to developers who
pass a ref prop to our component which can be useful when you have something
that needs to happen and is hard to deal with declaratively.NOTE: most of the time you should not needuseImperativeHandle
. Before you reach for it, really ask yourself whether there's any other way to accomplish what you're trying to do. Imperative code can sometimes be really hard to follow and it's much better to make your APIs declarative if possible. For more on this, read Imperative vs Declarative Programming