React Native中从数组取三个不重复随机单词的代码问题排查
问题:从数组获取三个不重复随机单词时过滤失效,重复单词仍出现
想要编写一个从数组中获取三个不重复随机单词的函数,参考相关内容实现数组过滤,但过滤功能未生效。实现代码如下:
takeThreeWords=()=>{ for(i=0;i<3;i++){ rand =(max, min=0)=> Math.floor(Math.random()*max-min) randomWord=()=> this.state.wordsBank[rand(this.state.wordsBank.length)] let aRandomWord = randomWord() this.setState(prevState=>({ wordsToUse:[...prevState.wordsToUse, aRandomWord], wordsBank: prevState.wordsBank.filter(word=>word!== aRandomWord) })) }
原本期望通过过滤确保wordsBank中的单词不会被重复选取,但实际运行时wordsToUse仍会出现重复单词,请问忽略了什么问题?
问题分析与解决方案
核心问题:setState的异步特性导致状态更新不同步
React的setState是异步操作,循环中连续调用setState时,每次循环里的prevState并不会立即反映前一次setState的更新结果。也就是说,三次循环里的prevState.wordsBank其实都是初始的数组状态,过滤操作并没有基于已经移除过元素的数组,自然无法避免重复选取。
其他次要问题
- 随机数函数计算错误:
rand函数的公式逻辑有误,正确的区间随机整数计算应该是Math.floor(Math.random() * (max - min)) + min,原写法可能会产生负数索引,导致取到错误的元素甚至undefined。 - 变量未声明导致全局污染:
rand和randomWord没有用let/const声明,会变成全局变量,属于不良编码习惯。 - 函数定义放在循环内冗余:每次循环都重新定义
rand和randomWord函数,完全没必要,应该提到循环外部。
修正后的代码实现
推荐先在内存中完成数组的随机选取和过滤,再一次性更新状态,避免异步更新带来的问题:
takeThreeWords = () => { // 复制原数组,避免直接修改state const remainingWords = [...this.state.wordsBank]; const selectedWords = []; // 定义随机数生成函数,放在循环外 const getRandomIndex = (max, min = 0) => { return Math.floor(Math.random() * (max - min)) + min; }; for (let i = 0; i < 3; i++) { if (remainingWords.length === 0) break; // 防止数组元素不足时出错 const randomIndex = getRandomIndex(remainingWords.length); const selectedWord = remainingWords.splice(randomIndex, 1)[0]; selectedWords.push(selectedWord); } // 一次性更新状态 this.setState({ wordsToUse: [...this.state.wordsToUse, ...selectedWords], wordsBank: remainingWords }); };
代码说明
- 先复制
wordsBank到内存数组remainingWords,后续操作都基于这个副本,确保每次选取都是从剩余元素中进行。 - 使用
splice方法直接从remainingWords中移除选中的元素,保证不会重复选取。 - 最后一次性调用
setState更新状态,避免异步更新的冲突。
内容的提问来源于stack exchange,提问作者Batchounet
相关产品推荐
相关产品推荐

