如何修复React刷新时先显有序项再显随机20项的代码问题
解决刷新页面先显示原顺序再切换随机项的问题
问题出在你把数组打乱逻辑放在了useEffect中——useEffect是组件挂载完成后才执行的,所以第一次渲染时用的是未打乱的原数组,等useEffect执行完修改数组后,组件才会重新渲染显示随机项,这就导致了闪屏现象。
修改方案
情况1:Myjson是本地静态数据
直接在useState的初始化函数中完成数组打乱和截取,这样组件第一次渲染时就会使用处理好的随机数组:
import { useState } from 'react'; // 组件内部 const [randomItems, setRandomItems] = useState(() => { // 先复制原数组,避免修改原Myjson(防止影响其他使用该数组的逻辑) const copiedArr = [...Myjson]; // Fisher-Yates 洗牌算法(修正了原代码的随机范围问题) for (let i = copiedArr.length - 1; i >= 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [copiedArr[i], copiedArr[j]] = [copiedArr[j], copiedArr[i]]; } // 截取前20个随机项 return copiedArr.slice(0, 20); }); // 渲染部分直接用处理好的randomItems {randomItems.map((item) => ( <Link href={item.ud} key={item.id} > {item.test} </Link> ))}
情况2:Myjson是动态获取的(比如props、API请求返回)
如果Myjson是动态变化的,就需要在useEffect中监听Myjson的变化,重新生成随机数组,同时可以加个加载状态避免空内容:
import { useState, useEffect } from 'react'; // 组件内部 const [randomItems, setRandomItems] = useState([]); useEffect(() => { if (!Myjson || Myjson.length === 0) return; const copiedArr = [...Myjson]; for (let i = copiedArr.length - 1; i >= 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [copiedArr[i], copiedArr[j]] = [copiedArr[j], copiedArr[i]]; } setRandomItems(copiedArr.slice(0, 20)); }, [Myjson]); // 渲染时判断状态,避免未加载时显示空 {randomItems.length > 0 ? ( randomItems.map((item) => ( <Link href={item.ud} key={item.id} > {item.test} </Link> )) ) : ( <div>加载中...</div> )}
关键注意事项
- 永远不要直接修改原数组(比如原代码直接操作
a = Myjson后打乱),一定要先浅拷贝([...Myjson]),否则会污染原数据,引发其他逻辑问题。 - 原代码的洗牌算法有个小问题:
Math.random() * i生成的随机数范围是0 ≤ j < i,会导致最后一个元素永远不会和自己交换,修正为Math.random() * (i + 1)才能覆盖所有索引。
内容的提问来源于stack exchange,提问作者a3egd
相关产品推荐
相关产品推荐

