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

Styled Components初始渲染className为何显示最终状态?

问题:Styled Components 初始渲染类名与状态不符的原因

环境信息

  • @types/styled-components: ^5.1.26

代码实现

index.tsx

import React, { useEffect, useState } from 'react';
import { ProfileHomeContainer } from './styled';

const ProfileHome: React.FC = () => {
  const [test, setTest] = useState(false);

  useEffect(() => {
    const my = document.getElementById('test');
    console.log(my);
    console.log(test);
    setTest(true);
  }, [test]);

  return (
    <ProfileHomeContainer id='test' test={test ? 1 : 0}>
    </ProfileHomeContainer>
  )
}

styled.ts

import styled from 'styled-components';

interface ProfileHomeContainerProps {
  test: number;
}

const ProfileHomeContainer = styled.div<ProfileHomeContainerProps>`
  display: flex;
  align-items: center;
  justify-content: center;
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100vh;
  background: rgba(0, 0, 0, 0.9);
  z-index: 1101;
  opacity: ${(props) => (props.test ? '1' : '0')};
  transition: 1s;
`;

对应全局CSS类

/* 对应opacity:0 */
.KBlzF{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;position:fixed;top:0;left:0;width:100%;height:100vh;background:rgba(0,0,0,0.9);z-index:1101;opacity:0;-webkit-transition:1s;transition:1s;}

/* 对应opacity:1 */
.goFgwQ{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;position:fixed;top:0;left:0;width:100%;height:100vh;background:rgba(0,0,0,0.9);z-index:1101;opacity:1;-webkit-transition:1s;transition:1s;}

控制台实际输出

<div id="test" class="sc-crXcEl goFgwQ">
false
<div id="test" class="sc-crXcEl goFgwQ">
true

预期输出

<div id="test" class="sc-crXcEl KBlzF">
false
<div id="test" class="sc-crXcEl goFgwQ">
true

疑问

首次执行useEffect时test状态为false,但组件却渲染了对应test为true的goFgwQ类,这一现象的原因是什么?


原因分析

  1. React的useEffect是在组件渲染完成、DOM挂载到页面后才执行的。初始渲染阶段,test为false,此时组件确实会渲染出带有KBlzF类的DOM节点。
  2. 但useEffect执行时,立刻调用了setTest(true),触发组件重新渲染。React会同步更新DOM,把类名替换成goFgwQ。
  3. 你在useEffect里打印DOM时,拿到的已经是更新后的节点;而console.log(test)打印的是当前useEffect闭包捕获的初始test值(false)——因为闭包保存的是当前渲染周期的状态,和后续更新后的DOM状态不同步。

简单来说:初始渲染的KBlzF节点刚挂载就被setTest(true)触发的重渲染覆盖了,你打印时只看到了最终更新后的DOM,但test还是初始值,所以出现了日志里的矛盾现象。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 20:36:38