Reputation: 10686
I need to access the ref to a textarea inside a component. Within the component, its easy enough:
const MyComponent = () => {
const inputRef = useRef();
return <textarea ref={inputRef} />
}
Now the ref is available within MyComponent and I can use it for some internal logic.
There are cases where I need to access the ref from the parent component as well. In that case, I can use forwardRef:
const MyComponent = React.forwardRef((props, ref) => {
return <textarea ref={ref} />
})
// In some parent
const MyParent = () => {
const inputRefFromParent = useRef();
return <MyComponent ref={inputRefFromParent} />
}
Now I can access to ref of the textarea
from the parent component, and use it for logic within the parent component.
I find myself in a situation where I need to do some internal logic with the ref within MyComponent
, but I may also need to get that ref from MyParent
. How can I do this?
Upvotes: 12
Views: 11654
Reputation: 13245
You can keep a ref
in the MyComponent
and expose what you would need in the parent component using useImperativeHandle hook using the ref
passed from the MyParent
.
Try like below. It exposes the focus method in the textarea to parent. And you can do any other internal things with the access to textAreaRef
.
import { useRef, forwardRef, useImperativeHandle } from "react";
const MyComponent = forwardRef((props, ref) => {
const textAreaRef = useRef();
// all the functions or values you can expose here
useImperativeHandle(ref, () => ({
focus: () => {
textAreaRef.current.focus();
}
}));
const internalFunction = () => {
// access textAreaRef
};
return <textarea ref={textAreaRef} />;
});
// In some parent
const MyParent = () => {
const inputRefFromParent = useRef();
// you can call inputRefFromParent.current.focus(); in this compoenent
return <MyComponent ref={inputRefFromParent} />;
};
Upvotes: 20
Reputation: 89234
To access a ref while also forwarding it:
useImperativeHandle
hook on the outer ref (which is being forwarded to) and pass a function that returns the current
property of the inner ref, which is the value that will be set to the current
property of the outer ref. This exposes the entire ref to consumers rather than selectively picking certain properties.import { forwardRef, useImperativeHandle, useRef } from 'react';
const MyComponent = forwardRef((props, outerRef) => {
const innerRef = useRef(null);
useImperativeHandle(outerRef, () => innerRef.current, []);
// remember to list any dependencies of the function that returns the ref value, similar to useEffect
return <textarea ref={innerRef} />
});
Or with TypeScript:
import { forwardRef, useImperativeHandle, useRef } from 'react';
const MyComponent = forwardRef<HTMLTextAreaElement>((props, outerRef) => {
const innerRef = useRef<HTMLTextAreaElement>(null);
useImperativeHandle(outerRef, () => innerRef.current!, []);
return <textarea ref={innerRef} />
});
Upvotes: 4
Reputation: 1544
What's working for me is:
export const MyComponent: FC<Props> = forwardRef<HTMLInputElement, Props>(
function myComponent(
{ /* ... */ }: Props,
forwardedRef
) {
const innerRef = useRef<HTMLInputElement | null>(null);
return (
<div>
<input ref={(instance: HTMLInputElement) => {
innerRef.current = instance;
if (typeof forwardedRef === "function") forwardedRef(instance);
else if (forwardedRef !== null) forwardedRef.current = instance;
}} />
</div>
)
}
)
Upvotes: 5
Reputation: 6748
You could do also the following:
const MyComponent = React.forwardRef((props, externalRef) => {
const internalRef = useRef<HTMLElement>();
const ref = useMemo(
() => externalRef || internalRef,
[externalRef, internalRef]
) as React.MutableRefObject<HTMLElement>;
return <textarea ref={ref} />
})
Upvotes: 3
Reputation: 10686
In addition to Amila's answer, I found another way to do it, by using a ref callback:
const MyComponent = React.forwardRef((props, parentRef) => {
const localRef = useRef();
return <textarea ref={ref => {
parentRef.current = ref;
localRef.current = ref;
}} />
})
So the callback ref keeps finer grain control of the ref to the textarea
, and simply assigns its value to both the local ref and the parent ref.
Upvotes: 9