Сбрасывается фокус при вводе текста в 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);
};
→ Ссылка