Enhance your input fields with wait logic
Input fields that wait for a user to finish typing before performing an action are common feature in web applications. They can be tricky to get working so I wanted to show how I incorporated a wait timer into my input fields.
In my case, I needed a field that waits for users to finish typing in a few places. I already had an input component made with some custom styling, so I decided to extend the wait logic as a customizable feature.
For my example, Im using React, Typescript and Material UI.
Below is the complete example, I'll step through the component piece by piece for the rest of the article.
interface IProps extends OutlinedTextFieldProps {
waitForInput: boolean
}
Here I'm defining an interface with a custom property that extends the type used by Material UI Outlined Text Field component. This way I can use the component the same way I normally would, it just has one extra property.
const { waitForInput, ...inputProps } = props
You'll get a console warning if you add an unknown property to a Material UI component, so I separate my custom property from the outlined text field ones.
const [waitEvent, setWaitEvent] = useState<React.ChangeEvent<HTMLInputElement>>(null)
This is where I store the text field onChange event while we wait for the user to stop typing.
useEffect(() => {
let timer = 0
if (waitEvent && waitForInput) {
timer = setTimeout(() => inputProps.onChange(waitEvent), 1000)
}
return () => clearTimeout(timer)
}, [waitEvent])
I leverage useEffect to handle my wait logic. It will rerun every time waitEvent is updated. If waitEvent and waitForInput are truthy, each change will reset the timeout to wait for 1 second.
const onChange = (event: React.ChangeEvent<HTMLInputElement>) => {
if (waitForInput) {
event.persist() <- only for React 16 and earlier
setWaitEvent(event)
} else {
inputProps.onChange(event)
}
}
Replacement for the standard onChange function. Adds a check for if we should use the wait logic or continue as normal.
return <TextField {...inputProps} onChange={onChange} />
return the standard Material UI text field component while spreading out all our properties. The onChange assignment should come after the spread of inputProps.
<ExtendedInput
waitForInput
variant="outlined"
label="Extended Input"
onChange={(e) => alert(e.target.value)}
/>
Now you can use the component exactly as you would if it was the original Material UI version. With the added waitForInput property available.
Thanks, Jesse! It’s a very specific use-case but it’s really useful (similar to using
debounce
). Thanks for the insights. I guess for the most “common” cases maybe theonBlur
built-in event is more suitable.Yeah if this was a vanilla application I would have used onBlur.