如何监听React状态数组中对象特定属性的变化?
需求:仅当数组对象的指定属性变化时触发服务器请求
我需要实现一个效果:只有当steps数组中对象的value属性发生变化时,才触发Hook把值发送到服务器。如果是disabled或active这类其他属性变化(且不会影响最终要发送的value集合),不执行服务器请求。
原状态示例:
const [steps, setSteps] = useState([ { id: 1, value: "value 123", // 仅此值变化时需要触发请求 disabled: false, active: true, }, { id: 2, value: "value 345", // 仅此值变化时需要触发请求 disabled: false, active: true, }, { id: 3, value: "value 678", // 仅此值变化时需要触发请求 disabled: false, active: true, }, ]);
我目前的实现方式是用单独的configuration状态来跟踪需要发送的值,代码如下,虽然能运行,但不确定是不是最优解:
const [configuration, setConfiguration] = useState({}); useEffect(() => { let updatedConfig = {}; steps.forEach((step) => { if (step.value && step.active) { updatedConfig[step.id] = step.value; } }); setConfiguration((prevConfig) => { // 对比新旧配置是否变化,再决定是否更新状态 const changed = JSON.stringify(prevConfig) !== JSON.stringify(updatedConfig); return changed ? updatedConfig : prevConfig; }); }, [steps]); useEffect(() => { console.log(configuration, "Send values to server!"); }, [configuration]);
优化方案
你的现有方案可行,但可以做两处优化,避免额外的状态存储和JSON.stringify带来的性能开销:
方案1:直接在依赖项中生成关键属性集合
不需要额外维护configuration状态,直接在useEffect的依赖数组里生成只包含id、value和active的数组(这三个属性会影响最终要发送的payload)。React会自动浅对比这个依赖项的变化,只有当这些属性变化导致payload改变时,才触发服务器请求。
useEffect(() => { // 生成需要发送到服务器的 payload const payload = steps.reduce((acc, step) => { if (step.value && step.active) { acc[step.id] = step.value; } return acc; }, {}); console.log(payload, "Send values to server!"); }, [steps.map(step => ({ id: step.id, value: step.value, active: step.active }))]);
方案2:用useRef缓存上次状态,手动对比
如果觉得依赖项中的map不够直观,可以用useRef缓存上次的关键数据,在useEffect内部手动判断是否需要触发请求:
const prevStepsKeyData = useRef([]); useEffect(() => { // 提取当前 steps 中影响 payload 的关键属性 const currentKeyData = steps.map(step => ({ id: step.id, value: step.value, active: step.active })); const prevKeyData = prevStepsKeyData.current; // 判断关键属性是否有变化 const hasChanged = JSON.stringify(currentKeyData) !== JSON.stringify(prevKeyData); if (hasChanged) { const payload = steps.reduce((acc, step) => { if (step.value && step.active) { acc[step.id] = step.value; } return acc; }, {}); console.log(payload, "Send values to server!"); // 更新缓存的上次状态 prevStepsKeyData.current = currentKeyData; } }, [steps]);
方案对比
- 原方案:多维护了一个
configuration状态,且JSON.stringify对比对象的方式在数据量大时会有性能损耗。 - 优化方案:避免了额外状态,直接聚焦于影响请求的关键属性,触发时机更精准,性能也更优。
内容的提问来源于stack exchange,提问作者Robbert
相关产品推荐
相关产品推荐

