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

React实现仅展示数组3个元素、倒计时结束随机更换元素

React实现列表仅展示3项+倒计时结束自动随机轮换方案

你可以按照以下步骤修改代码,直接落地需求:

核心修改逻辑

  • 将全量的5条事件数据抽为固定常量,避免组件每次渲染重新生成id导致本地存储数据异常
  • 实现无重复的随机抽取函数,每次从全量列表中拿到3条不重复的展示数据
  • 新增独立的本地存储字段保存当前正在展示的3条数据,页面初始化时自动完成首次随机抽取
  • 调整倒计时归零回调:重置所有按钮状态的同时,同步重新抽取3条新数据替换当前展示内容
  • 优化状态切换逻辑,改用元素唯一id匹配修改项,避免索引错位导致的状态异常
  • 渲染时直接遍历当前展示的3条数据,而非全量列表

可直接替换的完整代码

import { useEffect } from 'react';
import { v4 } from 'uuid'; // 按你项目实际的uuid导入路径调整
import useLocalStorage from 'use-local-storage';

// 把全量事件数据抽为组件外固定常量,id固定避免重复生成
const ALL_EVENTS = [
  {id: v4(), title: 'Apple iPhone 13 Pro Max 256Gb (небесно-голубой)', avatar: 'https://cdn-icons-png.flaticon.com/512/147/147144.png', statusItem: false},
  {id: v4(), title: '500 Stars', avatar: 'https://cdn-icons-png.flaticon.com/512/147/147144.png', statusItem: false},
  {id: v4(), title: 'Sony PlayStation 5 Digital Edition', avatar: 'https://cdn-icons-png.flaticon.com/512/147/147144.png', statusItem: false},
  {id: v4(), title: 'XBOX 360 Digital Edition', avatar: 'https://cdn-icons-png.flaticon.com/512/147/147144.png', statusItem: false},
  {id: v4(), title: 'Google Nexus Digital Edition', avatar: 'https://cdn-icons-png.flaticon.com/512/147/147144.png', statusItem: false}
];

// 随机抽取工具函数:从数组中取n个不重复元素
const getRandomItems = (arr, count = 3) => {
  const copy = [...arr];
  // Fisher-Yates 洗牌算法打乱数组
  for (let i = copy.length - 1; i > 0; i--) {
    const randomIndex = Math.floor(Math.random() * (i + 1));
    [copy[i], copy[randomIndex]] = [copy[randomIndex], copy[i]];
  }
  // 重置所有项的选中状态后返回前count条
  return copy.slice(0, count).map(item => ({...item, statusItem: false}));
};

const CurrentEventsItem = () => {
  const [timeLeft, setTimeLeft] = useLocalStorage('timer',  5 * 60);
  // 新增本地存储字段,保存当前展示的3条数据,初始化时自动随机抽取
  const [displayList, setDisplayList] = useLocalStorage('currentDisplayEvents', getRandomItems(ALL_EVENTS));

  const getPadTime = (time) => time.toString().padStart(2, '0');
  const minutes = getPadTime(Math.floor(timeLeft / 60));
  const seconds = getPadTime(timeLeft - minutes * 60);

  useEffect(() => {
    const interval = setInterval(() => {
      setTimeLeft((timeLeft) => (timeLeft >= 1 ? timeLeft - 1 : resetAndRefresh() ||  5 * 60));
    }, 1000);
    return () => clearInterval(interval); 
  }, []);

  // 优化状态切换逻辑,用id匹配避免索引错位
  const toggleActive = (id) => {
    const updatedList = displayList.map(item => 
      item.id === id ? {...item, statusItem: !item.statusItem} : item
    );
    setDisplayList(updatedList);
  };

  const toggleActiveStyles = (status) => {
    return status ? 'current__events__hot-price disabled' : 'current__events__hot-price';
  };
  
  const toggleActiveStylesBtns = (status) => {
    return status ? 'current__events__btn-green disabled' : 'current__events__btn-green';
  };

  // 倒计时归零的回调:重置状态+刷新展示列表
  const resetAndRefresh = () => {
    // 重新抽取3条新数据更新展示
    setDisplayList(getRandomItems(ALL_EVENTS));
  };

  return (
    <>
    <div className='current__events__wrapper'>
        {/* 直接遍历当前展示的3条数据渲染 */}
        {displayList.map((item) => 
            <div className="current__events__hot-price__item" key={item.id}>
                <div className={toggleActiveStyles(item.statusItem)}>
                    <h5 className="current__events__card-title__large">Hot Price</h5>
                </div>
                <div className="current__events__image">
                    <img src={item.avatar} alt='user' className="rounded-circle" width='75' height='75'/>
                </div>
                <div className="current__events__info">
                    <h4 className="current__events__title__middle">{item.title}</h4>
                </div>
                
                <div className="current__events__timer">
                    <span>{minutes}</span>
                    <span>:</span>
                    <span>{seconds}</span>
                </div>

                <button 
                  className={toggleActiveStylesBtns(item.statusItem)} 
                  onClick={() => toggleActive(item.id)} 
                  disabled={item.statusItem}
                >
                  СДЕЛАТЬ ХОД
                </button> 
            </div> 
        )}
    </div>
    </>
  )
}

export default CurrentEventsItem;

关键注意点

  • 原代码把全量数据存在localStorage中,每次组件初始化都会重新生成uuid,会导致本地存储的旧数据和新数据id不匹配,抽成外部常量后id只在首次加载时生成一次,稳定性更高
  • 随机抽取使用洗牌算法实现,不会出现同一次展示3条内容重复的问题
  • 改用id作为列表key和状态匹配依据,避免因为列表顺序变化、索引错位导致的样式、点击事件异常
  • 每次抽取新的展示数据时会自动重置所有项的statusItem为false,不需要额外遍历重置按钮状态

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 05:21:22