使用StreamProvider时Widget无值变更却多次重建的问题
一、赋值theme后MyWidget多次重建的原因
这是两个因素叠加的结果:
StreamProvider的状态变化触发MyApp多次重建
你用ref.watch(streamProvider)监听了StreamProvider,这个Provider的状态会先处于AsyncLoading,收到Stream发送的1后切换为AsyncData(1)。这两次状态变更会让MyApp(ConsumerWidget)重建两次。每次重建都生成全新的ThemeData实例
MyApp每次build时,都会新建ThemeData、TextButtonThemeData以及OutlinedButton.styleFrom的实例——哪怕配置完全一样,这些都是全新的对象。Flutter会对比MaterialApp前后的theme是否相等,由于这些内部子对象都是新的,ThemeData的相等判断会返回false,所以MaterialApp会认为主题变了,通知所有依赖Theme.of(context)的组件(也就是MyWidget)重建。再加上Flutter初始化过程中一些内部的build触发逻辑,最终就导致MyWidget被重建了12次。如果不赋值theme,MaterialApp用的是默认主题单例,不会触发主题更新;如果MyWidget不读取Theme,哪怕主题变了也不会重建,所以只会build一次。
二、ref.watch改ref.read后只重建一次的原因
ref.watch是监听Provider状态变化,一旦Provider状态更新,当前Widget就会被强制重建。而ref.read只是一次性读取Provider当前值,不会建立监听关系——哪怕后续StreamProvider的状态从加载态变成数据态,MyApp也不会因此重建。
这样MyApp只会在初始化时build一次,生成一次ThemeData,之后不会再重建,MyWidget自然也只会被build一次。
内容的提问来源于stack exchange,提问作者Praveena

