为何useState变量currentId无法传入数组find方法?如何动态查找元素?
问题
我需要通过id值从数组中查找对象,使用Array.find()方法时,直接用常量id=3能正常获取对应元素:
const onUpdateExercise = (e) => { e.preventDefault() const form = e.target var id = 3 const ex = exercises.find(item => item.id === id) console.log(ex); }
但把id换成用useState声明的currentId(值同样为3)后,代码无法找到对应元素:
const onUpdateExercise = (e) => { e.preventDefault() const form = e.target var id = 3 const ex = exercises.find(item => item.id === currentId) // currentId是useState变量,值为3 console.log(ex); }
完整代码如下:
const [currentId, setCurrentId] = useState(0) const [exercises, setExercises] = useState([ { id: 1, name: 'Bench press', defaultSets: 4, defaultReps: 8 }, { id: 2, name: 'Overhead press', defaultSets: 4, defaultReps: 8 }, { id: 3, name: 'Triceps push down', defaultSets: 4, defaultReps: 12 }, { id: 4, name: 'Skullcrusher', defaultSets: 4, defaultReps: 12 } ]) const onUpdateExercise = (e) => { e.preventDefault() const form = e.target var id = 3 // currentId点击按钮后值为3 const ex = exercises.find(item => item.id === currentId) console.log(ex); }
请问为何currentId无法传入find方法?以及动态查找数组元素的最优方法是什么?
解答
一、currentId无法匹配元素的原因
- 类型不匹配:
数组中item.id是数字类型,但currentId可能是字符串类型(比如从表单、URL参数获取的值默认是字符串),===严格相等判断会因类型不同返回false,导致找不到元素。 - 闭包捕获旧值:
onUpdateExercise函数可能捕获了更新前的currentId闭包值(比如初始值0),即使后续currentId被更新为3,函数依然使用旧值进行匹配。
可以在find前添加console.log(typeof currentId, currentId, typeof exercises[0].id),快速对比类型和数值是否一致,定位问题。
二、动态查找数组元素的最优方法
统一类型,修复匹配逻辑:
如果currentId是字符串,转换为数字后再匹配:const ex = exercises.find(item => item.id === Number(currentId))或者在设置
currentId时直接存储为数字类型:setCurrentId(Number(targetValue))大数组优化:转为对象映射:
当数组元素较多时,find遍历的时间复杂度为O(n),可以用useMemo将数组转为以id为键的对象映射,实现O(1)时间复杂度的查找:const exerciseMap = useMemo(() => { return exercises.reduce((map, item) => { map[item.id] = item return map }, {}) }, [exercises]) // 直接通过id获取元素 const ex = exerciseMap[currentId]解决闭包问题:用useRef保存最新值:
如果是闭包导致捕获旧值,用useRef同步最新的currentId:const currentIdRef = useRef(currentId) useEffect(() => { currentIdRef.current = currentId }, [currentId]) // 查找时使用ref的current属性 const ex = exercises.find(item => item.id === currentIdRef.current)
内容的提问来源于stack exchange,提问作者Avijit Palit
相关产品推荐
相关产品推荐

