How to set focus on a TextField\input using a Formik form when initialValues are passed through\bound to props.object?

Leniel Maccaferri picture Leniel Maccaferri · Feb 1, 2020 · Viewed 7.9k times · Source

I have Formik form with this TextField from @material-ui/core:

<TextField
    autoFocus
    fullWidth
    name='name'
    label='Name'
    variant="outlined"
    onChange={handleChange("name")}
    helperText={errors.name ? errors.name : "What's your name?"
    error={errors.name}
    touched={touched.name}
    value={values.name}
/>

This works great when the form loads for the 1st time with initialValues set to an empty user object. The Name input will be focused.

However when loading the form with an existing user object (during Edit operation) it loads all the fields correctly but there's no focus anymore.

This form is inside a stateless functional component and props.user comes from a parent component.

Any ideas on how to set focus in this case? Is there any place where I can hook up to call focus?

####### Edit 1 #######

I tried using useEffect but it is fired before the input field is actually updated with the value...

useEffect(() =>
{
    debugger;

    textInput.focus(); // at this point the input field hasn't gotten the value yet.
})

My guess is that I need to hold a ref inside the parent component...

Answer

Leniel Maccaferri picture Leniel Maccaferri · Feb 1, 2020

Got it working after debugging for some time...

I used a snippet of code taken from Run side effect when a prop changes w/Hooks and added a debugger statement to be able to check the input element:

let input = null

useEffect(() =>
{
    console.log('rendered!')

    if (input)
    {      
        debugger;

        input.focus()
    }

}, [props.user])

Note the props.user passed as argument... this means that anytime props.user changes, the useEffect hook will fire.

When setting ref on <TextField>:

ref={(i) => { input = i }}

as shown in many places when dealing with React JS focus, it was trying to focus on the TextField's <div> parent element from Material-UI. The real input is inside this <div>.

So the correct prop to set in TextField is inputRef:

inputRef={(i) => { input = i }}

This related answer led me in the right direction.