gpt4 book ai didi

javascript - React Portal 输入更改删除元素

转载 作者:行者123 更新时间:2023-11-30 14:04:07 27 4
gpt4 key购买 nike

我创建了这支笔来演示它:https://codepen.io/no1melman/pen/WWyJqQ

基本上我有这个门户:

const ChatArea = ({ children }) => {
const el = document.createElement("div");
el.classList.add('chatbox')
const root = document.getElementById("rootus");

useEffect(() => {
root.appendChild(el);
return () => root.removeChild(el);
}, []);

return createPortal(children, 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>
)
}

出于某种原因,当您开始输入时,聊天框的主体似乎消失了...我已将日志放入 useEffect 中以查看是否是它的原因,但它没有显示我的想法

最佳答案

这里有两个问题:

第一期是

useEffect(() => {
root.appendChild(el);
return () => root.removeChild(el);
}, []);

现在根据钩子(Hook)原则,依赖项应该与钩子(Hook)内使用的变量相匹配。如果不使用,react 将不会在下次运行该效果。

所以在您的情况下,当您单击“打开聊天”时,它会打开聊天框。效果运行并渲染带有输入框的门户。

当你输入第一个字母时,onChange 发生了

它触发了 ChatArea 的重新渲染,理想情况下它应该再次运行效果,但没有运行,因为依赖数组为空并且 React 不知道何时重新渲染。所以效果第一次运行一次在 chatArea 运行 UI 的地方,下一次,效果没有运行,因为依赖项数组是空白的。

这一行:

返回 createPortal(children, el);//指的是创建的新 el但没有附加到 DOM。因此,在聊天框内的 UI 上看不到任何内容。

引用此链接:do not miss dependencies React hooks 常见问题解答部分很棒 :)

第二期:

理想情况下,不应每次都创建新的 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>

Ui was not coming up proper in the stackoverflow code snippet, so I had to edit somethings in styling. you can have a look at code pen codepen linkaccording to your original styling

关于javascript - React Portal 输入更改删除元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55782548/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com