React嵌套数组重渲染问题:Quiz应用选项重复洗牌
问题解决:Quiz应用选项重复洗牌的问题
问题根源
你遇到的核心问题是:每次组件重渲染(比如用户选择选项时),question?.pairs.map(...)都会生成一个全新的数组,导致useShuffle Hook的依赖项(array)发生变化,触发useMemo重新执行,进而重新洗牌选项。而直接传入pairs数组时,只要原pairs未被修改,依赖项就不会变化,因此不会重复洗牌。
解决方案
方案1:提前缓存提取后的选项数组
在组件中先用useMemo缓存提取出的questionOption和answerOption数组,再传给useShuffle,确保只有原pairs变化时才重新生成这些数组:
// 在Question组件中 const questionOptions = useMemo(() => { return question?.pairs.map(pair => pair.questionOption) ?? []; }, [question?.pairs]); const answerOptions = useMemo(() => { return question?.pairs.map(pair => pair.answerOption) ?? []; }, [question?.pairs]); const shuffledLeftSideOptions = useShuffle(questionOptions); const shuffledRightSideOptions = useShuffle(answerOptions);
方案2:修改useShuffle Hook,依赖原pairs数组
直接让useShuffle依赖原pairs数组,在内部完成选项提取和洗牌,避免外部传递每次都变化的数组:
// 修改为针对Connections类型的专用Hook export const useShuffleConnectionsOptions = (question?: IConnectionsQuestionData) => { return useMemo(() => { if (!question) return { left: [], right: [] }; const left = shuffleArray(question.pairs.map(pair => pair.questionOption)); const right = shuffleArray(question.pairs.map(pair => pair.answerOption)); return { left, right }; }, [question?.pairs]); }; // 在Question组件中使用 const { left: shuffledLeftSideOptions, right: shuffledRightSideOptions } = useShuffleConnectionsOptions(question);
额外注意:确保shuffleArray是纯函数
要保证shuffleArray不会修改原数组,避免引发意外状态变化,推荐使用Fisher-Yates洗牌算法的纯函数实现:
function shuffleArray<T>(array: T[]): T[] { // 创建原数组副本,避免修改原数据 const newArray = [...array]; for (let i = newArray.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [newArray[i], newArray[j]] = [newArray[j], newArray[i]]; } return newArray; }
修改后,只有原question.pairs数组发生变化时,选项才会重新洗牌,组件因用户操作重渲染时不会触发重复洗牌。
内容的提问来源于stack exchange,提问作者Антон Стецюра
相关产品推荐
相关产品推荐

