React Hooks - Input loses focus when 1 character is typed in
While answer by Kais will solve the symptoms, it will leave the cause unaddressed. It will also fail if there are multiple inputs - which one should autofocus itself on rerender then?
The issue happens when you define a component (FormComponent
) inside the scope of another function which is called each render of your App
component. This gives you a completely new FormComponent
each time your App
component is rerendered and calls useState
. That new component is then, well, without focus.
Personally I would feel agains returning components from a hook. I would instead define a FormComponent
component, and only return state from useForm state.
But, a working example closest to your original code could be:
// useForm.js
import React, { useState } from "react";
// Define the FormComponent outside of your useForm hook
const FormComponent = ({ setState, state, label }) => (
<form>
<label htmlFor={label}>
{label}
<input
type="text"
id={label}
value={state}
placeholder={label}
onChange={e => setState(e.target.value)}
/>
</label>
</form>
);
export default function useForm(defaultState, label) {
const [state, setState] = useState(defaultState);
return [
state,
<FormComponent state={state} setState={setState} label={label} />,
setState
];
}
// App.js
import useForm from "./useForm";
export default function App() {
const [formValue, Form] = useForm("San Francisco, CA", "Location");
return (
<>
<h1>{formValue}</h1>
{Form}
</>
);
}
Here's a sandbox
The above answers didn't work for me. The solution that worked for me was much simpler and, for that reason, less obvious.
The Problem
Essentially, the value that I was changing with the input was also being used for each key
in a list of inputs.
Hence, when I updated the value the key
would change and React would detect that it's different relative to the last key and create a new input in its place. As a new input it wouldn't focus on itself.
However, by using autoFocus
it would automatically focus on the newly created input. But the issue wasn't fixed as it was obvious that the input was continually going through a cycle of un-focus and focus.
Here's an article demonstrating the problem.
The Fix
Update the key
to an unchangeable value so React would have a stable reference to the list items. In my case I just updated it to the index. This is not ideal (React docs recommend using a stable ID), but in my situation it was okay because the order of the items won't change.
When you enter any text in input box. Parent Component is also re-rendering. So you need to make focus on input manually.
For this, use autoFocus
in input tag
<input
type="text"
id={label}
value={state}
placeholder={label}
onChange={e => setState(e.target.value)}
autoFocus
/>