Input теряет focus при вводе одного символа (React)
Есть например массив data который через map() создаёт разметку в приложении на React.
data: [
{
id: 1,
firstName: "Ксения",
middleName: "Сергеевна",
},
{
id: 2,
firstName: "Константин",
middleName: "Сергеевич",
},
];
Вот есть 2 input:
<input
type="text"
value={firstName}
name="firstName"
onChange={(event) => changeData(event)}
/>
<input
type="text"
value={middleName}
name="middleName"
onChange={(event) => changeData(event)}
/>
Хочу изменить состояние в одном из input значения которых соответствуют значениям из объектов в массиве.
const changeData = (event) => {
setData(
data.map((item) =>
item.id === detailId // Ловит нужный объект в массиве.
? { ...item, [event.target.name]: event.target.value }
: item
)
);
};
Проблема заключается в том, что при вводе одного любого символа в любой из input он сразу теряет фокус(focus).
Значения в state меняются правильно. Я так понимаю что при вводе любого символа компонент перерисовывается и поэтому фокус теряется. Но как это обойти, пока не получается. Спасибо за ответы)
Ответы (4 шт):
Представлено недостаточно кода, но поделюсь своим решением аналогичной проблемы. У меня инпуты создавались в стрелочной функции:
const FirstStage = () => (
<>
<label htmlFor="courseNameInput">Название курса</label>
<TextField
key="courseNameInput"
variant="filled"
size="small"
onChange={(event) => setCourseName(event.target.value)}
value={courseName}
name="courseNameInput"
/> <>...
Далее эта функция рендерилась подобным образом:
return (
<FirstStage />
)
Данная ошибка пропала после того, как начал рендерить следующим образом:
return (
{FirstStage()}
)
У меня была точно такая же проблема, в моём случае дело было в том что в функции которая перерисовывала всё дерево создавался рут элемент.
было:
export let rerenderTree = (state) => {
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>
);
};
стало:
const root = ReactDOM.createRoot(document.getElementById("root"));
export let rerenderTree = (state) => {
root.render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>
);
};
строка ->
const root = ReactDOM.createRoot(document.getElementById("root"));
была вынесена за пердел функции. Это исправило проблему фокуса.
введите сюда код
Потеря фокуса происходит из-за того, что вы используете map для отрисовки input-ов, точнее из-за того что вы меняете состояние input который находится вне input как компонента. Как лечить? Есть два рецепта:
Отказаться от map:
export const Component = () => { const [firstPerson, setFirstPerson] = useState({ firstName: "Ксения", middleName: "Сергеевна", }); const [secondPerson, setSecondPerson] = useState({ firstName: "Константин", middleName: "Сергеевич", }); return ( <> <input type="text" value={firstPerson.firstName} name="firstName" onChange={(event) => setFirstPerson((prevState) => ({ ...prevState, firstName: event.target.value, })) } /> <input type="text" value={firstPerson.middleName} name="middleName" onChange={(event) => setFirstPerson((prevState) => ({ ...prevState, middleName: event.target.value, })) } /> <input type="text" value={secondPerson.firstName} name="firstName" onChange={(event) => setSecondPerson((prevState) => ({ ...prevState, firstName: event.target.value, })) } /> <input type="text" value={secondPerson.middleName} name="middleName" onChange={(event) => setSecondPerson((prevState) => ({ ...prevState, middleName: event.target.value, })) } /> </> ); };
2.Сделать отдельный компонент в котором будет свой state и потом уже использовать map:
const Field = ({ firstName, middleName }) => {
const [data, setData] = useState({
firstName,
middleName,
});
return (
<>
<input
type="text"
value={data.firstName}
name="firstName"
onChange={(event) =>
setData((prevState) => ({
...prevState,
firstName: event.target.value,
}))
}
/>
<input
type="text"
value={data.middleName}
name="middleName"
onChange={(event) =>
setData((prevState) => ({
...prevState,
middleName: event.target.value,
}))
}
/>
</>
);
};
export const Component = () => {
const data = [
{
id: 1,
firstName: "Ксения",
middleName: "Сергеевна",
},
{
id: 2,
firstName: "Константин",
middleName: "Сергеевич",
},
];
return (
<>
{data.map((element) => (
<Field
key={element.id}
firstName={element.firstName}
middleName={element.middleName}
/>
))}
</>
);
};
Проблема заключается в том, что при вводе одного любого символа в любой из input он сразу теряет фокус(focus).
Как уже писали выше - ТС предоставил мало информации о содеянном.
На своем примере демонстрирую что все работает и фокус с инпутов никуда не девается. При этом никаких особых действий не нужно делать.
//
function Itm({obj, fn}){
const act = e => fn(a => a.map(o => o.id === obj.id
? { ...o, [e.target.name]: e.target.value }
: o
))
return <li>
<input
type="text"
value={obj.firstName}
name="firstName"
onChange={act}
/>
<input
type="text"
value={obj.middleName}
name="middleName"
onChange={act}
/>
</li>
}
//
function App(){
const [arr, setArr] = React.useState([])
React.useEffect(_ => {
setArr(data())
}, [])
return <ul>
{arr.map(o => <Itm key={o.id} obj={o} fn={setArr} />)}
</ul>
}
//
function data(){
return [
{
id: 1,
firstName: "Ксения",
middleName: "Сергеевна",
},
{
id: 2,
firstName: "Константин",
middleName: "Сергеевич",
},
]
}
const domContainer = document.querySelector('#like_button_container');
const root = ReactDOM.createRoot(domContainer);
root.render(<App />);
<div id="like_button_container"></div>
<script src="https://unpkg.com/react@18/umd/react.development.js"
crossorigin>
</script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"
crossorigin>
</script>