You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何避免Next.js 14中Chat组件展开/收起时卸载重挂载

问题:Next.js 14中避免Chat组件展开/关闭时被卸载重挂载

在Next.js 14应用中存在一个Chat组件,要求不能被卸载或重挂载。当前移动端设置了展开/关闭按钮,但每次操作都会导致组件销毁并重新渲染,对话记录丢失,求解决方法。

现有代码

// 断点样式
const FirstRoot = styled(Paper)(({ theme }) => ({
  marginInline: theme.spacing(0.5),
  overflowY: "auto",
  [theme.breakpoints.down("md")]: {
    height: "100%",
    width: "100%",
  },
  [theme.breakpoints.between("md", "lg")]: {
    height: "100%",
    width: "70%",
  },
  [theme.breakpoints.up("lg")]: {
    height: "100%",
    width: "70%",
  },
}));

// Chat容器样式
interface ChatContainerProps {
  isChatOpen: boolean;
}

const ChatContainer = styled(Box)<ChatContainerProps>(({ isChatOpen }) => ({
  position: "fixed",
  top: 0,
  left: 0,
  width: "100%",
  height: isChatOpen ? "100vh" : 0,
  display: isChatOpen ? "block" : "none",
  backgroundColor: "white",
  zIndex: 1201,
}));

// 展开/关闭状态
const [isChatOpen, setIsChatOpen] = useState(false);

const toggleChat = (): void => {
  setIsChatOpen((prevState) => !prevState);
};

// 渲染部分
<FirstRoot>
  {children}
  {!isChatOpen && (
    <Box
      sx={{
        display: { xs: "block", sm: "block", md: "none" }, // 仅移动端显示按钮
        zIndex: 1201,
        position: "fixed",
        bottom: 25,
        right: 16,
        borderRadius: "50%",
        overflow: "hidden",
      }}
    >
      {/* 打开Chat的按钮 */}
      <Image
        alt="Open Chat"
        height={80}
        onClick={toggleChat}
        src="/kerry_avatar.png"
        style={{ cursor: "pointer" }}
        title="Open Chat"
        width={80}
      />
    </Box>
  )}
  {/* isChatOpen为true时渲染Chat组件 */}
  {isChatOpen ? (
    <Box
      sx={{
        display: { xs: "block", sm: "block", md: "none" },
      }}
    >
      <ChatContainer isChatOpen={isChatOpen}>
        <Chat onClose={toggleChat} /> {/* onClose关闭Chat */}
      </ChatContainer>
    </Box>
  ) : null}
</FirstRoot>

解决方案

核心问题是条件渲染导致Chat组件被卸载,只要让组件始终存在,用CSS控制显示/隐藏即可保留组件状态。

1. 修改渲染逻辑,移除Chat组件的条件渲染

将原来仅在isChatOpen为true时渲染Chat的逻辑,改为始终渲染Chat组件,依赖ChatContainer的样式控制显示与隐藏。

修改后的渲染代码:

<FirstRoot>
  {children}
  {!isChatOpen && (
    <Box
      sx={{
        display: { xs: "block", sm: "block", md: "none" },
        zIndex: 1201,
        position: "fixed",
        bottom: 25,
        right: 16,
        borderRadius: "50%",
        overflow: "hidden",
      }}
    >
      <Image
        alt="Open Chat"
        height={80}
        onClick={toggleChat}
        src="/kerry_avatar.png"
        style={{ cursor: "pointer" }}
        title="Open Chat"
        width={80}
      />
    </Box>
  )}
  {/* 始终渲染Chat组件,通过容器样式控制显示隐藏 */}
  <Box
    sx={{
      display: { xs: "block", sm: "block", md: "none" },
    }}
  >
    <ChatContainer isChatOpen={isChatOpen}>
      <Chat onClose={toggleChat} />
    </ChatContainer>
  </Box>
</FirstRoot>

2. 优化容器样式(可选)

如果希望隐藏时完全不占用空间且不可交互,可以保留现有ChatContainer的样式逻辑:

  • isChatOpen为true时:height: 100vh、display: block
  • isChatOpen为false时:height: 0、display: none

这样组件在DOM中始终存在,但隐藏时不会被用户感知,同时保留内部状态(对话记录)。

其他可选方案

  • 状态提升:将Chat组件的对话记录状态提升到父组件,即使Chat被卸载,重新渲染时也能从父组件获取状态恢复。但这种方法不如CSS控制直接,且会增加父组件的状态复杂度。
  • 使用React Context:将对话记录存入Context,Chat组件从Context读取/更新状态,即使组件卸载重挂载也能恢复数据。但同样不如保持组件挂载的方案高效。

内容的提问来源于stack exchange,提问作者Ignacio García

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 10:20:58