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

React中如何实现数组元素单次随机排序(可使用useEffect)

问题根因分析
  • 你当前的写法核心问题是:打乱后的答案没有持久化存储,每次组件重渲染都会重新生成原始顺序的答案数组
  • 你写的useEffect完全不生效:useEffect执行时机在组件渲染完成之后,此时你修改的allAnswers只是当前渲染周期的临时局部变量,既不会触发重新渲染,下一次组件重渲染时又会重新生成未打乱的、正确答案在末尾的allAnswers数组
  • 如果直接删掉useEffect把shuffle写在顶层,每次点击按钮触发组件状态更新、组件重渲染时都会重新执行shuffle,自然就会出现点击后答案顺序错乱的问题
修复方案

核心逻辑:用useState存储打乱后的答案数组,仅在当前题目(props.result)变化时才重新生成并打乱,同个题目下无论多少次重渲染都用同一套顺序的答案。

具体实现代码

import { useState, useEffect, useMemo } from 'react'
import { nanoid } from 'nanoid'

// 可直接使用你自己实现的shuffle函数
function shuffle(array) {
  return [...array].sort(() => Math.random() - 0.5)
}

function Question(props) {
  const correctId = useMemo(() => nanoid(), [props.result.correct_answer])
  const incorrectIds = useMemo(() => [nanoid(), nanoid(), nanoid()], [props.result.incorrect_answers])

  // 用state存打乱后的答案列表,仅当题目数据变化时才重新生成
  const [shuffledAnswers, setShuffledAnswers] = useState([])

  useEffect(() => {
    // 先整理所有答案的纯数据,不直接存JSX方便后续处理
    const rawAnswers = [
      ...props.result.incorrect_answers.map((answer, index) => ({
        text: answer,
        type: 'incorrect',
        id: incorrectIds[index]
      })),
      {
        text: props.result.correct_answer,
        type: 'correct',
        id: correctId
      }
    ]
    // 打乱后存入state
    setShuffledAnswers(shuffle(rawAnswers))
  }, [props.result, correctId, incorrectIds]) // 依赖仅为题目相关数据,只有换题才会重新执行打乱

  // 抽离公共的按钮渲染逻辑
  const renderAnswerButton = (answer) => {
    return (
      <button 
        value={answer.type}
        id={answer.id}
        onClick={e => {
          changeClass(correctId, 'correct')
          if (answer.type === 'incorrect') {
            changeClass(answer.id, 'incorrect')
          }
          props.answerQuestion(e, answer.type)
        }}
      >
        {answer.text}
      </button>
    )
  }

  return (
    <div className="question">
      <h3>{props.result.question}</h3>
      <div className="answers">
        {shuffledAnswers.map(answer => renderAnswerButton(answer))}
      </div>
    </div>
  )
}
更简洁的替代写法

如果你不想额外声明state和useEffect,也可以直接用useMemo实现,效果完全一致:

const shuffledAnswers = useMemo(() => {
  const rawAnswers = [
    ...props.result.incorrect_answers.map((answer, index) => ({
      text: answer,
      type: 'incorrect',
      id: incorrectIds[index]
    })),
    {
      text: props.result.correct_answer,
      type: 'correct',
      id: correctId
    }
  ]
  return shuffle(rawAnswers)
}, [props.result, correctId, incorrectIds])

内容的提问来源于stack exchange,提问作者Jake Clifford

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 03:06:04