2026-07-29 20:18:13
Riverpod 的 select 机制通过选择性监听状态变化来优化性能。当使用 ref.watch(personStateProvider.select((p) => p.name)) 时,只有当 name 属性发生变化时,才会触发监听组件的刷新,从而避免不必要的重建。
select 的实现原理:
select 方法返回一个 _AlwaysAliveProviderSelector 对象,该对象继承自 _ProviderSelector,并在其中实现了 addListener 方法。
addListener 方法主要完成两部分工作:
注册回调:在 stateProvider 中注册回调,当 state 改变时执行 _selectOnChange 方法。
封装回调:将注册的回调封装为 _SelectorSubscription 对象,该对象最终返回到 widget 的 element 中,并保存在 _dependencies 中。
_selectOnChange 的处理逻辑:
使用 select 的回调函数获取具体要监听的值(如 name 或 age),并将其包装成 Result 对象。
比较旧值和新值,如果不同,则执行 listener(即 markNeedsBuild),触发组件刷新。
状态变化流程:
当 state 被重新赋值(如 age 增加 1)时,personProviderElement 执行 setState,进而触发 _notifyListeners。
_notifyListeners 遍历所有监听器,执行 listener.listener,即 _selectOnChange。
_selectOnChange 通过 select 回调获取新值,并比较新旧值。如果不同,则执行 listener(markNeedsBuild),触发组件刷新。
select 的本质:
select 在 providerElement 和 WidgetElement 之间添加了一层过滤机制。providerElement._dependents 不再直接添加 WidgetElement.markNeedsBuild,而是通过 _AlwaysAliveProviderSelector._selectOnChange 判断是否需要执行 WidgetElement.markNeedsBuild。
通过这种方式,select 实现了对状态变化的精细控制,避免了因无关状态变化导致的组件不必要的刷新,从而提升了应用性能。