Здесь есть два вопроса:
Первый номер
useEffect(() => {
root.appendChild(el);
return () => root.removeChild(el);
}, []);
Теперь согласно принципу ловушек зависимость должна соответствовать используемым переменным внутри ловушки. Если не использовать реакцию, эффект не запустится в следующий раз.
ТАК в вашем случае, когда вы нажимаете на открыть чат, он открывает окно чата. эффект запустился и визуализировал портал с полем ввода.
Когда вы набрали первую букву, и onChange произошло
Это вызвало повторное рендеринг ChatArea, которое в идеале должно было бы снова запустить эффект, но не было запущено, поскольку массив зависимостей пуст и реакция не имеет представления о том, когда re-render.so эффект запускался один раз в первый раз где chatArea запускал монтированный пользовательский интерфейс и в следующий раз эффект не запустился, поскольку массив зависимостей пуст.
Эта строка:
return createPortal (children, el); // ссылается на новый созданный el
но не привязанный к DOM. Следовательно, ничего не видно на интерфейсе внутри чата.
Перейдите по этой ссылке: Не пропустите зависимости Реагируйте на разделы FAQ по хукам, они великолепны:)
2-й выпуск:
В идеале, новый div не должен создаваться каждый раз. Сохранять элемент "div" при последовательном повторном просмотре
Посмотрите эту реализацию: я знаю, что могут быть другие способы ее реализации
Отзывы приветствуются.
const {
render,
createPortal
} = ReactDOM;
const {
useState,
useEffect,
useRef
} = React;
const ChatArea = ({
children
}) => {
const el = document.createElement("div");
el.classList.add('chatbox')
// This el above will be different in each render
// root will remain same, ideally root and chatdiv should be passed as props
const root = document.getElementById("rootus");
// this val and setVal is done to toggle render the chart area after
// chatDiv is updated
const [val, setVal] = useState(true)
const chatDiv = useRef(null)
// First useEffect to persist the div
useEffect(() => {
if (!chatDiv.current) {
chatDiv.current = el
setVal(!val)
}
}, [chatDiv])
useEffect(() => {
root.appendChild(chatDiv.current);
return () => {
return root.removeChild(chatDiv.current)
}; // you are removing it
}, [chatDiv, root]);
if (chatDiv.current) {
return createPortal(children, chatDiv.current)
}
return null
// In your case as the return happened first and found out the el
};
const ChatBox = () => {
const [reply, setReply] = useState('');
const handleReply = (e) => {
e.preventDefault();
setReply(e.target.value);
}
return ( <
ChatArea >
<
div className = "chat-title" > Bot Convo < /div>
<
div className = "chat-convo" > < /div>
<
div className = "chat-reply" >
<
input type = "text"
value = {
reply
}
onChange = {
handleReply
}
/> <
button > Send < /button> <
/div> <
/ChatArea>
)
}
const NavBar = ({}) => ( <
div className = "navbar" >
<
div > Home < /div> <
div > Somewhere < /div> <
/div>
);
const Main = () => {
const [showChat, setShowChat] = useState(false);
const openChat = () => {
setShowChat(true);
};
const chatterbox = showChat ? ( < ChatBox / > ) : null;
return ( <
div className = "container" >
<
h2 > Main < /h2> <
p >
It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout.The point of
using Lorem Ipsum is that it has a more - or - less normal distribution of
letters, as opposed to using 'Content here, content here', making it look like readable English.Many desktop publishing packages and web page editors now use Lorem Ipsum as their
default model text, and a search
for 'lorem ipsum'
will uncover many web sites still in their infancy.Various versions have evolved over the years, sometimes by accident, sometimes on purpose(injected humour and the like). <
/p> <
p style = {
{
display: "flex",
justifyContent: "center"
}
} >
<
button onClick = {
openChat
} > Open Chat < /button> <
/p> <
p style = {
{
display: "flex",
flexDirection: "column",
justifyContent: "center",
backgroundColor: "red"
}
} >
{
chatterbox
} < /p> <
/div>
);
};
const App = ({}) => ( <
div className = "app" >
<
NavBar / >
<
Main / >
<
/div>
);
render( < App / > , document.getElementById("rootus"));
body {
font-family: Raleway;
}
* {
box-sizing: border-box;
}
#rootus {
position: relative;
height: 100vh;
display: flex;
justify-content: center;
}
.navbar {
display: flex;
justify-content: center;
}
.navbar>div {
padding: 10px;
}
.navbar>div:hover {
background-color: gray;
cursor: pointer;
}
.container {
width: 960px;
}
.app {
display: flex;
flex-direction: column;
align-items: center;
}
.chatbox {
width: 400px;
height: 200px;
position: absolute;
bottom: 0;
border: 2px solid black;
background: white;
display: flex;
flex-direction: column;
}
.chat-title {
background: black;
color: white;
}
.chat-convo {
flex: 1;
display: flex;
}
.chat-reply {
display: flex;
border-top: 1px solid black;
}
.chat-reply>input {
width: 80%;
padding: 8px;
border: none;
outline: none;
}
.chat-reply>button {
outline: none;
border: none;
flex: 1;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.6/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.6/umd/react-dom.production.min.js"></script>
<div id="rootus">
</div>
Пользовательский интерфейс неправильно отображался во фрагменте кода stackoverflow, поэтому я
пришлось редактировать что-то в стиле. Вы можете взглянуть на кодовое перо
кодовая ссылка в соответствии с вашим оригинальным стилем