Как установить фокус на поле ввода (инпут) при изменении чекбокса?
Даны чекбокс <input type="checkbox">
и поле ввода <input type="text">
. Хочу фокусировать поле ввода, когда пользователь отмечает чекбокс — так пользователю будет понятно, что от него ожидается ввод текста, если чекбокс включён.
Напишу компонент, который показывает чекбокс и поле ввода, значение для поля ввода сохраню с помощью хуков useState
и useCallback
:
export const App = () => {
const [value, setValue] = useState("");
const handleInputChange = useCallback(
(event) => setValue(event.target.value),
[]
);
return (
<main>
<input type="checkbox" />
<input type="text" value={value} onChange={handleInputChange} />
</main>
);
};
Добавлю обработчик на изменение чекбокса: покажу алерт с новым значением. Обработчик события вызывается с объектом event
, в свойстве target
лежит элемент, который вызвал событие, в моем случае event.target
— чекбокс. Новое значение чекбокса можно получить из его свойства checked
: event.target.checked
:
export const App = () => {
const [value, setValue] = useState("");
const handleInputChange = useCallback(
(event) => setValue(event.target.value),
[]
);
const handleChange = useCallback((event) => {
alert(event.target.checked);
}, []);
return (
<div className="App">
<input type="checkbox" onChange={handleChange} />
<input type="text" value={value} onChange={handleInputChange} />
</div>
);
};
Теперь, при изменении чекбокса, установлю фокус в поле ввода. У элементов, которые могут получать фокус ввода, есть метод focus
. Чтобы вызвать этот метод у поля ввода, его нужно найти - в этом поможет механизм ref-ов и хук useRef
.
Создам ref и передам его пропсой полю ввода:
const inputRef = useRef();
// ...
<input
type="text"
value={value}
onChange={handleInputChange}
ref={inputRef}
/>;
React, после рендера элементов, поместит в inputRef
ссылку на поле ввода. У всех ref-ов есть свойство current
, в котором хранится значение ref-а. Воспользуюсь им, чтобы вызвать метод focus
у элемента, для этого в обработчик изменения чекбокса добавлю inputRef.current.focus()
:
export const App = () => {
const [value, setValue] = useState("");
const inputRef = useRef();
const handleInputChange = useCallback((e) => setValue(e.target.value), []);
const handleChange = useCallback(
(e) => {
if (e.target.checked) {
inputRef.current.focus();
}
},
[inputRef]
);
return (
<div className="App">
<input type="checkbox" onChange={handleChange} />
<input
type="text"
value={value}
onChange={handleInputChange}
ref={inputRef}
/>
</div>
);
};
Иногда может оказаться, что решение с использованием ref-ов слишком сложное. Тогда можно попробовать найти нужный элемент с помощью DOM API — например, document.querySelector
. Чтобы найти элемент используя querySelector
, его нужно как-то идентифицировать, добавлю ему id
. Затем, в обработчике изменения чекбокса, заменю ref на вызов document.querySelector
:
export const App = () => {
const [value, setValue] = useState("");
const handleInputChange = useCallback((e) => setValue(e.target.value), []);
const handleChange = useCallback((e) => {
if (e.target.checked) {
document.querySelector("#input").focus();
}
}, []);
return (
<div className="App">
<input type="checkbox" onChange={handleChange} />
<input
id="input"
type="text"
value={value}
onChange={handleInputChange}
/>
</div>
);
};
Использовать documenent.querySelector
нежелательно:
- нет гарантии, что найдет нужный элемент — сколько еще может быть на странице элементов с таким же селектором?
- компонент перестанет работать в окружении, где нет
document
. - querySelector будет искать элемент по всему дереву, а React сохранит ссылку на элемент в ref-е при рендере, что быстрее.
Поэтому вариант с ref-ами более стабильный и предсказуемый.
Top comments (0)