Сбрасывается фокус при вводе текста в input'е контролируемого компонента
Я создал кнопку, которая открывает модальное окно. Само же модальное окно реализовано с помощью порталов. В модальном окне есть input, который я зафиксировал по правилам контролируемого компонента: его value указан как value из state и есть метод при onChange, который меняет этот самый state.value. Проблема в том, что при вводе одного символа в этот input сразу же сбрасывается фокус с него. Пробовал разные решения, которые были предложены поисковиком: и атрибут key ставил (как самим полям, так и целом модальному окну), и писал модальное окно не выводя его в отдельный компонент. Ничего не помогло
Примерный код (в реальности же вместо хука useReducer используется Redux. Тем не менее, и этот вариант не работает):
import React, { useReducer, useState, useEffect } from "react";
import ReactDOM from "react-dom";
const initialState = {
subject: "",
};
const reducer = (state, action) => {
switch (action.type) {
case "SUBJECT":
return {
subject: action.payload,
};
default:
return state;
}
};
const App = (props) => {
const [state, dispatch] = useReducer(reducer, initialState);
const [isVisible, setVisible] = useState(false);
const setSubject = (event) => {
dispatch({
type: "SUBJECT",
payload: event.target.value,
});
};
return (
<div>
<div>
<strong>{state.subject}</strong>
</div>
<button onClick={() => setVisible(true)}>Show modal</button>
{isVisible && (
<Modal
setSubject={setSubject}
value={state.subject}
setVisible={setVisible}
/>
)}
</div>
);
};
const Portal = (props) => {
const div = document.createElement("div");
useEffect(() => {
document.body.appendChild(div);
return () => {
document.body.removeChild(div);
};
}, [div]);
return ReactDOM.createPortal(props.children, div);
};
const Modal = (props) => {
return (
<Portal>
<div
style={{
position: "fixed",
top: 0,
bottom: 0,
left: 0,
right: 0,
background: "rgba(0, 0, 0, 0.4)",
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
>
<div
style={{
background: "#ffffff",
width: "400px",
height: "400px",
}}
>
<input type='text' value={props.value} onChange={props.setSubject} />
<button onClick={() => props.setVisible(false)}>Close</button>
</div>
</div>
</Portal>
);
};
CodePen: ссылка
Ответы (1 шт):
const Portal = (props) => {
const div = React.useMemo(()=>document.createElement("div"),[]);
React.useEffect(() => {
document.body.appendChild(div);
return () => {
document.body.removeChild(div);
};
},[]);
return ReactDOM.createPortal(props.children, div);
};