Let’s say I have a component that accepts an element (likely to be <input />
) and I want to programmatically update the value
of it after 15 seconds. This is my first thought on how to do it:
const MyComponent = (myInput: JSX.Element) => {
useEffect(() => {
setTimeout(() => {
myInput instanceof HTMLInputElement && myInput.value = "new value";
}, 15000);
});
return <></>;
};
Now, this doesn’t work because myInput
is a React Node / JSX Element and not a raw HTMLInputElement
. To get around this my 2nd thought is to use ref
somehow but myInput
isn’t rendered so I’m unable to ref={myRef}
.
Is there any way I can access the underlying HTML element at runtime?
My reason for this is because I’m using a library that has rather limited functionality and I’m trying to make it work correctly with react-hook-form
. As RHF relies on onChange
, I need to trigger a "change"
event (I used myInput.value =
above to simplify the example but really I just want the raw element to trigger an event)
2
Answers
I recommend you don’t try to modify the dom directly. React has no idea that you’re doing that so it can’t take your changes into account when it does its calculations.
But there are a couple options. First, you could clone the input and give it an extra value prop. I adjusted your props to destructure the object, and now we’ve got a state to track the value:
This approach does mean though that you can only work with elements that accept a
value
prop. It’s also a bit of a pain in typescript.So a second option is to change the props you accept so that instead of passing in an element, you pass in a function. The function will accept the value and return an element. The term you’ll see for this pattern is a "render prop". For example:
That will make it flexible to be used with other components that need to use different props or add custom logic. Eg:
Potential Solution: