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

为何CSS过渡在函数调用组件时生效,组件标签调用时失效?

问题:组件标签形式调用的侧边栏过渡效果失效

我实现了一个带有展开/收起过渡效果的侧边栏。当以函数形式调用Sidebar组件时(示例中的侧边栏1),过渡效果正常运行;但以组件标签形式调用该组件时(示例中的侧边栏2),过渡效果完全失效。请问示例2中的过渡效果为何无法生效?

代码示例

JavaScript

const App = (props) => {
  const [sidebarCollapsed, setSidebarCollapsed] = React.useState(false);

  const Sidebar = ({ bg, ...props }) => {
    const width = sidebarCollapsed ? "0px" : "200px";

    return (
      <div
        style={{
          backgroundColor: bg,
          height: "100px",
          width: width,
          transitionDuration: "500ms"
        }}
      />
    );
  };

  return (
    <div>
      <div>
        {/* Sidebar 1 -> function */}
        {Sidebar({ bg: "blue" })}

        {/* Sidebar 2 -> component */}
        <Sidebar bg="red" />

        <button onClick={() => setSidebarCollapsed(!sidebarCollapsed)}>
          Toggle sidebar
        </button>
      </div>
    </div>
  );
};

ReactDOM.render(<App />, document.getElementById("root"));

HTML

<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="root"></div>

原因分析

核心问题出在**Sidebar组件定义在App组件内部**:

  • 函数形式调用Sidebar({ bg: "blue" }):本质是执行普通函数,返回的DOM元素会被React直接复用、更新,状态变化时能触发正常的CSS过渡。
  • 组件标签形式<Sidebar bg="red" />:React会将其识别为组件,但App每次因sidebarCollapsed状态变化重渲染时,都会重新定义一遍Sidebar函数。React判断组件类型时会认为这是一个全新组件,于是卸载旧的<Sidebar>实例,重新挂载新实例——新实例直接渲染目标宽度(0或200px),跳过了过渡需要的渐变过程,自然没有动画效果。

解决方法

方法1:将Sidebar移到App外部定义

保证组件引用在App重渲染时不会变化:

const Sidebar = ({ bg, collapsed }) => {
  const width = collapsed ? "0px" : "200px";
  return (
    <div
      style={{
        backgroundColor: bg,
        height: "100px",
        width: width,
        transitionDuration: "500ms"
      }}
    />
  );
};

const App = (props) => {
  const [sidebarCollapsed, setSidebarCollapsed] = React.useState(false);

  return (
    <div>
      <div>
        {Sidebar({ bg: "blue", collapsed: sidebarCollapsed })}
        <Sidebar bg="red" collapsed={sidebarCollapsed} />
        <button onClick={() => setSidebarCollapsed(!sidebarCollapsed)}>
          Toggle sidebar
        </button>
      </div>
    </div>
  );
};

ReactDOM.render(<App />, document.getElementById("root"));

方法2:用useCallback缓存内部组件

如果必须在App内部定义Sidebar,可以通过useCallback固定组件函数的引用:

const App = (props) => {
  const [sidebarCollapsed, setSidebarCollapsed] = React.useState(false);

  const Sidebar = React.useCallback(({ bg }) => {
    const width = sidebarCollapsed ? "0px" : "200px";
    return (
      <div
        style={{
          backgroundColor: bg,
          height: "100px",
          width: width,
          transitionDuration: "500ms"
        }}
      />
    );
  }, [sidebarCollapsed]);

  return (
    <div>
      <div>
        {Sidebar({ bg: "blue" })}
        <Sidebar bg="red" />
        <button onClick={() => setSidebarCollapsed(!sidebarCollapsed)}>
          Toggle sidebar
        </button>
      </div>
    </div>
  );
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 10:45:46