How can I use a React ref as a mutable instance, with Typescript? The current property appears to be typed as read-only.
I am using React + Typescript to develop a library that interacts with input fields that are NOT rendered by React. I want to capture a reference to the HTML element and then bind React events to it.
const inputRef = useRef<HTMLInputElement>(); const { elementId, handler } = props; // Bind change handler on mount/ unmount useEffect(() => { inputRef.current = document.getElementById(elementId); if (inputRef.current === null) { throw new Exception(`Input with ID attribute ${elementId} not found`); } handler(inputRef.current.value); const callback = debounce((e) => { eventHandler(e, handler); }, 200); inputRef.current.addEventListener('keypress', callback, true); return () => { inputRef.current.removeEventListener('keypress', callback, true); }; });
It generates compiler errors: semantic error TS2540: Cannot assign to 'current' because it is a read-only property.
I also tried const inputRef = useRef<{ current: HTMLInputElement }>();
This lead to this compiler error:
Type 'HTMLElement | null' is not assignable to type '{ current: HTMLInputElement; } | undefined'. Type 'null' is not assignable to type '{ current: HTMLInputElement; } | undefined'.
useRef can only be null, or the element object. I then put the h1Ref variable inside the ref property of my H1 element. After the first render React. useRef will return an object with a property key called current .
The useRef Hook allows you to persist values between renders. It can be used to store a mutable value that does not cause a re-render when updated. It can be used to access a DOM element directly.
useRef can be used to store local mutable value in a component. It doesn't participate in rerendering (unline state data). useMemo is used to memoize (like we do in Dynamic Programming, concept wise) and skip recalculation.
The error "Cannot assign to 'current' because it is a read-only property" occurs when we initialize a ref with a null value and don't include null in its type. To solve the error, include null in the ref's type, e.g. const ref = useRef<string | null>(null) .
Yeah, this is a quirk of how the typings are written:
function useRef<T>(initialValue: T): MutableRefObject<T>; function useRef<T>(initialValue: T|null): RefObject<T>;
If the initial value includes null
, but the specified type param doesn't, it'll be treated as an immutable RefObject
.
When you do useRef<HTMLInputElement>(null)
, you're hitting that case, since T
is specified as HTMLInputElement
, and null
is inferred as HTMLInputElement | null
.
You can fix this by doing:
useRef<HTMLInputElement | null>(null)
Then T
is HTMLInputElement | null
, which matches the type of the first argument, so you hit the first override and get a mutable ref instead.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With