【发布时间】:2023-02-07 20:15:54
【问题描述】:
我正在使用带有选择的状态通知程序和状态通知程序提供程序来仅将重建应用于对象中的特定字段。但无论我选择与否,整个小部件都会重建。
我有以下示例代码来简化我的问题:
final counterProvider =
StateNotifierProvider<CounterState, Counter>((ref) => CounterState());
class Counter {
int count1;
int count2;
Counter(this.count1, this.count2);
}
class CounterState extends StateNotifier<Counter> {
CounterState() : super(Counter(0, 0));
void inc1() => state = Counter(state.count1 + 1, state.count2);
void inc2() => state = Counter(state.count1, state.count2 + 1);
}
和以下消费者小部件:
class TestWidget extends ConsumerWidget {
const TestWidget({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) => Scaffold(
body: Column(
children: [
Text(ref.watch(counterProvider.select((value) {
print("rebuilt counter 1 Text with val: ${value.count1}");
return value.count1.toString();
}))),
Text(ref.watch(counterProvider.select((value) {
print("rebuilt Counter 2 Text with val: ${value.count2}");
return value.count2.toString();
}))),
ElevatedButton(
onPressed: () => ref.read(counterProvider.notifier).inc1(),
child: const Text("Inc 1")),
ElevatedButton(
onPressed: () => ref.read(counterProvider.notifier).inc2(),
child: const Text("Inc 2"))
],
));
}
我很期待按inc1() 按钮不重建第二个文本。只有第一个。
但是当我按 3 次 inc1 时控制台中的输出如下:
I/flutter (19394): rebuilt counter 1 Text with val: 0
I/flutter (19394): rebuilt Counter 2 Text with val: 0
D/EGL_emulation(19394): app_time_stats: avg=417.64ms min=8.70ms max=4924.00ms count=13
I/flutter (19394): rebuilt counter 1 Text with val: 1
I/flutter (19394): rebuilt Counter 2 Text with val: 0
I/flutter (19394): rebuilt counter 1 Text with val: 1
I/flutter (19394): rebuilt Counter 2 Text with val: 0
D/EGL_emulation(19394): app_time_stats: avg=78.42ms min=2.63ms max=1171.43ms count=18
I/flutter (19394): rebuilt counter 1 Text with val: 2
I/flutter (19394): rebuilt Counter 2 Text with val: 0
I/flutter (19394): rebuilt counter 1 Text with val: 2
I/flutter (19394): rebuilt Counter 2 Text with val: 0
D/EGL_emulation(19394): app_time_stats: avg=34.74ms min=2.47ms max=721.10ms count=25
I/flutter (19394): rebuilt counter 1 Text with val: 3
I/flutter (19394): rebuilt Counter 2 Text with val: 0
I/flutter (19394): rebuilt counter 1 Text with val: 3
I/flutter (19394): rebuilt Counter 2 Text with val: 0
我期待在控制台中:
I/flutter (19394): rebuilt counter 1 Text with val: 0
I/flutter (19394): rebuilt Counter 2 Text with val: 0
D/EGL_emulation(19394): app_time_stats: avg=417.64ms min=8.70ms max=4924.00ms count=13
I/flutter (19394): rebuilt counter 1 Text with val: 1
D/EGL_emulation(19394): app_time_stats: avg=78.42ms min=2.63ms max=1171.43ms count=18
I/flutter (19394): rebuilt counter 1 Text with val: 2
D/EGL_emulation(19394): app_time_stats: avg=34.74ms min=2.47ms max=721.10ms count=25
I/flutter (19394): rebuilt counter 1 Text with val: 3
那么我对select()函数有什么理解不正确?
以及为什么第一个文本虽然发生了一次更改却重建了两次?
【问题讨论】:
-
你想分离状态,就像这里的状态包含两个计数值
Counter,要更新状态,你需要分配新的实例。 -
究竟在哪里分配一个新实例?如果你指的是
inc1()函数,我已经分配了一个新实例。如果还有哪里那么你能告诉我你的意思到底是哪里吗? -
我的意思是一旦你 `state = Counter..` 它就创建了新的实例并且两个值都变成了新的对象
-
是的,这是正确的。我正在尝试遵循不可变状态管理的原则。你是说我不能用不可变的状态管理来执行我想做的事情吗?