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类,这一现象的原因是什么?
原因分析
- React的
useEffect是在组件渲染完成、DOM挂载到页面后才执行的。初始渲染阶段,test为false,此时组件确实会渲染出带有KBlzF类的DOM节点。 - 但
useEffect执行时,立刻调用了setTest(true),触发组件重新渲染。React会同步更新DOM,把类名替换成goFgwQ。 - 你在
useEffect里打印DOM时,拿到的已经是更新后的节点;而console.log(test)打印的是当前useEffect闭包捕获的初始test值(false)——因为闭包保存的是当前渲染周期的状态,和后续更新后的DOM状态不同步。
简单来说:初始渲染的KBlzF节点刚挂载就被setTest(true)触发的重渲染覆盖了,你打印时只看到了最终更新后的DOM,但test还是初始值,所以出现了日志里的矛盾现象。
内容的提问来源于stack exchange,提问作者Yoonlang
相关产品推荐
相关产品推荐

