React.js中如何实现类似AngularJS的值变化监听功能?
React中实现AngularJS $watch等价的值变化监听方案
React没有提供和AngularJS $watch 完全对应的全局脏检查API,根据你使用的组件写法不同,可以通过生命周期或内置钩子实现完全一致的监听效果,你代码里的深度监听、新旧值比对、条件触发逻辑都可以完整覆盖。
函数组件(主流推荐写法)
函数组件通过useEffect实现值变化的副作用触发,搭配useRef存储上一次的渲染值,就能拿到和$watch一致的新旧值参数:
import { useEffect, useRef } from 'react'; // 组件内部,注意这部分代码要写在组件函数顶层 const prevRateModeRef = useRef(undefined); useEffect(() => { const newVal = rateMode; const oldVal = prevRateModeRef.current; // 对齐原代码的判断逻辑 if (newVal !== oldVal && timeRange !== "") { if (typeof onRateCallback !== 'undefined') { onRateCallback(chartDataObject, newVal); } updateChart(timeRange); } // 执行完逻辑后更新存储的旧值,供下一次变化比对 prevRateModeRef.current = newVal; }, [rateMode, timeRange, onRateCallback, chartDataObject]);
- 如果监听的
rateMode是字符串、数字这类基础类型,React默认的浅比较就可以准确捕获变化,对应$watch不传第三个参数的场景。 - 如果
rateMode是对象、数组这类引用类型,需要对齐原代码第三个参数true的深度监听效果,只需要在判断逻辑里加入新旧值的深比较即可,只有值真的发生变化时再执行业务代码,避免引用地址变化导致的无效触发。
类组件(旧版本React写法)
类组件直接在componentDidUpdate生命周期中做值比对即可,这个生命周期天然能拿到更新前的props、state,不需要额外存储旧值:
import React from 'react'; class YourComponent extends React.Component { // ...组件自身的state、方法定义 componentDidUpdate(prevProps, prevState) { // 如果rateMode存在state中就从state取值,存在props中就从props取值 const newVal = this.state.rateMode; const oldVal = prevState.rateMode; if (newVal !== oldVal && this.state.timeRange !== "") { if (typeof this.props.onRateCallback !== 'undefined') { this.props.onRateCallback(this.state.chartDataObject, newVal); } this.updateChart(this.state.timeRange); } } }
深度监听的逻辑直接写在判断条件里即可,不需要额外传参标记,灵活度比$watch更高。
注意事项
- 原AngularJS代码里
typeof $scope.onRateCallback != undefined存在写法问题,typeof返回的是字符串类型,正确判断应该是typeof xxx !== 'undefined',上述示例已经修正了这个问题。 - React的监听逻辑是显式声明依赖的,不会做全局Scope脏检查,性能比
$watch更好,注意useEffect的依赖数组要覆盖回调里用到的所有外部值,避免拿到过期的闭包值。
内容的提问来源于stack exchange,提问作者Khoa Nguyen
相关产品推荐
相关产品推荐

