如何在React组件return中渲染useState存储的对象状态?
报错根因
JSX 不支持直接渲染普通 JavaScript 对象。你代码里直接在模板中写{ctime},而ctime是存储了seconds/minutes/hours/days四个字段的对象,React 无法将对象转为可展示的DOM节点,就会抛出你看到的错误。
除此之外你的原有代码还存在3个逻辑问题,会导致倒计时无法正常运行:
- 时间差值计算逻辑写在组件顶层,仅在组件首次加载时执行一次,后续定时器触发不会重新计算最新的时间差
- 小时计算的除数写错,把
1000误写为100,计算出的小时数值完全错误 - useEffect 未传入依赖数组,会在每次组件重渲染时重复创建定时器,造成内存泄漏;同时定时器内直接传入旧的
ctime值更新状态,永远拿不到最新的时间结果
修正后完整代码
import React, { useState, useEffect } from 'react'; function Counter(){ const targetDate = '1 Jan 2023'; // 封装时间差计算逻辑,每次调用重新获取当前时间计算 const calcTimeLeft = () => { const targetTime = new Date(targetDate).getTime(); const currTime = new Date().getTime(); const diff = targetTime - currTime; // 倒计时结束时返回0值,避免出现负数 if (diff <= 0) { return { days: 0, hours: 0, minutes: 0, seconds: 0 } } const seconds = Math.floor((diff % (1000*60)) / 1000); const minutes = Math.floor((diff % (1000*60*60)) / (1000*60)); // 修正原代码的除数笔误 const hours = Math.floor((diff % (1000*60*60*24)) / (1000*60*60)); const days = Math.floor(diff / (1000*60*60*24)); return { seconds, minutes, hours, days } } const [ctime , setCTime] = useState(calcTimeLeft()); useEffect(() =>{ // 每秒重新计算时间差,更新状态 const interval = setInterval(() => setCTime(calcTimeLeft()), 1000); // 组件卸载时清除定时器,空依赖数组保证effect仅在挂载/卸载时执行 return () => clearInterval(interval); }, []) return( <div> <h1>Countdown</h1> {/* 分别读取对象属性渲染,不直接输出整个对象 */} <div> <span>{ctime.days} 天 </span> <span>{ctime.hours} 时 </span> <span>{ctime.minutes} 分 </span> <span>{ctime.seconds} 秒</span> </div> </div> ) } export default Counter;
核心修改点
- 渲染状态对象时,通过
ctime.days/ctime.hours这类属性访问语法,取出对象里的数字类型原始值做渲染,符合React的子元素规则 - 把时间差计算抽为独立函数,定时器触发时重新执行计算,保证倒计时数值每秒更新为最新结果
- 给useEffect传入空依赖数组,避免重复创建定时器;组件卸载时清除定时器,避免内存泄漏
- 补了倒计时结束的边界判断,修正了小时计算的笔误
内容的提问来源于stack exchange,提问作者Mahmoud Sabbagh
相关产品推荐
相关产品推荐

