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

React中通过setter修改div样式导致组件内容丢失问题排查

问题分析与修复方案

核心问题

你的代码存在三个关键错误,导致点击按钮后组件内容异常:

  1. 组件定义与Hooks使用违规
    DraggableElement 定义在 AppWindow 内部,每次 width 状态更新时,这个组件会被重新创建,导致其内部的 Draggable 钩子重复执行,破坏拖拽逻辑的状态,进而引发元素渲染异常。同时,直接在组件函数内部调用 Draggable(dragRef, dragRefParent) 不符合React Hooks使用规范(Hooks必须以use开头且在组件顶层调用),会导致refs和拖拽逻辑的状态管理混乱。

  2. 子组件参数接收错误
    MaximizeButton 组件的参数接收方式错误,你直接把props对象当成了givenWidth值。点击按钮时,实际传入setWidth的是一个对象而非数值,导致width状态变成对象,style={{width: width}}失效,容器宽度异常,内容看起来"丢失"。

  3. 全屏实现逻辑缺陷
    当前仅设置宽度为固定值(600),没有实现真正的全屏(占满屏幕宽高),且缺少明确的单位处理(虽然React对数字会自动加px,但明确写出更清晰,便于适配百分比/vw等场景)。


修复后的代码

import { useRef, useState, useEffect } from "react";
import Draggable from "./hooks/draggable";

// 将DraggableElement移到外部,避免每次渲染重新创建组件
const DraggableElement = ({ dragElement, parentElement, width }) => {
  const dragRef = useRef(null);
  const dragRefParent = useRef(null);

  // 用useEffect包裹Draggable调用,确保仅在refs就绪时执行,同时支持清理
  useEffect(() => {
    if (dragRef.current && dragRefParent.current) {
      const cleanup = Draggable(dragRef, dragRefParent);
      return cleanup;
    }
  }, [dragRef, dragRefParent]);

  return (
    <div
      ref={dragRefParent}
      className="draggable-parent dialog"
      style={{ 
        width: `${width}px`, 
        height: width === window.innerWidth ? '100vh' : 'auto' 
      }}
    >
      <div ref={dragRef} className="draggable-child">
        {dragElement}
      </div>
      {parentElement}
    </div>
  );
};

// 正确解构props参数
const MaximizeButton = ({ givenWidth, onClick }) => {
  return (
    <button onClick={() => onClick(givenWidth)}>MAXIMIZE</button>
  );
};

export function AppWindow() {
  const [width, setWidth] = useState(400);

  // 实现全屏/还原的切换逻辑
  const handleMaximize = () => {
    setWidth(prev => prev === window.innerWidth ? 400 : window.innerWidth);
  };

  return (
    <DraggableElement
      width={width}
      dragElement={
        <div className="app-title">
          Application Title goes here
          <div className="app-topbar">
            <button onClick={handleMaximize}>Maximize</button>
            <MaximizeButton givenWidth={window.innerWidth} onClick={setWidth} />
          </div>
        </div>
      }
      parentElement={
        <div>
          <div className="contents">
            Contents of the application here
          </div>
        </div>
      }
    />
  );
}

关键修复说明

  • 组件拆分:将DraggableElement移到AppWindow外部,避免状态更新时组件重复创建,保留拖拽逻辑的状态。
  • Hooks规范:用useEffect包裹Draggable调用,确保仅在refs就绪时执行,同时支持清理函数避免内存泄漏。
  • 参数修正:MaximizeButton正确解构props,确保传入的是数值而非对象。
  • 全屏逻辑优化:新增切换逻辑,点击按钮在默认宽度和屏幕宽度之间切换,同时设置高度为100vh实现全屏,非全屏时高度自动适配内容。

内容的提问来源于stack exchange,提问作者JSJB

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 01:20:38