React Hooks学习:无事件触发时如何更新useState并检测数组变化
解决方案
你可以使用React内置的useEffect Hook实现需求,它的作用就是在指定依赖发生变化时,自动执行回调函数。你需要监听的依赖是影响step计算的两个变量:datas.UserAchievements和themeToCompare,这两个值任意一个发生变化,就自动触发createNewMapOfDatas执行。
注意事项
原有createNewMapOfDatas的写法存在逻辑问题:每次调用都往已有step数组后追加内容,重复执行会导致数据冗余。建议修改为每次执行时先生成全新的step数组,再赋值给state,避免旧数据干扰。
修正后代码
import { useState, useEffect } from 'react'; // 记得导入useEffect export const BadgeSubojectivesCategoryCompletion = ({ themeToCompare, indexSkillCount, datas, src, titleSubobjective, descriptionSubobjective }) => { const [step, setStep] = useState([]); let errorMsg = "Error: "; const {data: countSkills, error, loading} = useQuery<SkillsDataResult>(GET_COUNT_SKILLS_DATA); // 新增useEffect,监听依赖变化自动触发函数 useEffect(() => { // 只有datas存在且有UserAchievements字段时才执行逻辑 if (!datas?.UserAchievements) return; createNewMapOfDatas(); }, [datas?.UserAchievements, themeToCompare]); // 依赖项:变化就触发回调 if(loading){ return 'Loading...'; } if(error){ return errorMsg.concat(error.name, ", Message: ", error.message); } const createNewMapOfDatas = () => { // 每次执行先生成新数组,避免旧数据冗余 const newStep = []; for (let i = 0; i < datas.UserAchievements.length; i++) { const item = datas.UserAchievements[i]; if (item.label.localeCompare("categoryCompletion") == 0) { if (item.additionalInfo.localeCompare(themeToCompare) == 0) { newStep.push(item.step); } } } // 直接赋值新数组,不需要用函数式更新 setStep(newStep); } const max = Math.max(...step); return ( <div className={styles.BadgeProfileSubObjectivesMiddle}> <p>{countSkills.Category[indexSkillCount].CurrentSkillsAndDesires_aggregate.aggregate.count}/{max}</p> </div> ); };
补充说明
useEffect默认会在组件首次挂载完成后执行一次,之后每次依赖项发生浅比较变化时都会再次执行,完全符合你的需求。- 如果父组件更新
datas.UserAchievements时没有修改数组引用(只是修改数组内元素),浅比较会检测不到变化,此时建议父组件更新数组时传入新的数组引用(比如用[...oldArray]生成新数组),或者临时把依赖项改为JSON.stringify(datas.UserAchievements)做深比较兜底。
内容的提问来源于stack exchange,提问作者Pasteque
相关产品推荐
相关产品推荐

