如何从 RiverPod 中的构造函数初始化 stateProvider
How to initialize stateProvider from constructor in RiverPod
基本上,我想将初始构造函数值设置为 StateProvider
,以便我可以在其子部件中使用它。
final stateProvider = StateProvider((ref) => "default");
class ExampleWidget extends ConsumerWidget {
ExampleWidget({required String text}){
// how to override default hear as
// stateProvider = text
}
@override
Widget build(BuildContext context, ScopedReader watch) {
return Column(
children: [
Text(watch(stateProvider).state),
Container(
child: ChildWidget(),
),
],
);
}
}
class ChildWidget extends ConsumerWidget {
@override
Widget build(BuildContext context, ScopedReader watch) {
return Container(
child: Text(watch(stateProvider).state),
);
}
}
那么我该如何实现呢?
我试过this但是状态值没有更新。
编辑----------------
与riverpod_hook
& hooks_flutter
final stateProvider = StateProvider((ref) => "default");
class ExampleWidget extends HookWidget {
@override
Widget build(BuildContext context) {
WidgetsBinding.instance?.addPostFrameCallback((_) {
useEffect((){
context.read(stateProvider).state = "new value";
},[]);
});
final state = useProvider(stateProvider).state;
return Column(
children: [
Text(state),
],
);
}
}
上面的代码抛出了这个错误
Hooks can only be called from the build method of a widget that mix-in
挂钩``
所以我尝试在build方法下初始化是这样的
useEffect((){
context.read(stateProvider).state = "new value";
},[]);
但上面的代码抛出以下错误:
The following Error was thrown building ExampleWidget(dirty, dependencies: [UncontrolledProviderScope]):
Instance of 'Error'
我只想初始化一次值,这就是为什么我想使用 useEffect
钩子。
您无法在构造函数中正常访问提供程序。您也不应该直接在构建方法中更新状态,因为这可能会导致构建错误(在您设置会导致另一次重建的状态之前小部件尚未完成构建)。
您应该可以使用 addPostFrameCallback
在构建小部件后更改状态。
例如:
class ExampleWidget extends ConsumerWidget {
const ExampleWidget({required String text});
final String text;
@override
Widget build(BuildContext context, ScopedReader watch) {
WidgetsBinding.instance?.addPostFrameCallback((_) {
context.read(stateProvider).state = text;
});
return Column(
children: [
Text(watch(stateProvider).state),
Container(
child: ChildWidget(),
),
],
);
}
}
关于您的编辑:
Hooks can only be called from the build method of a widget that mix-in Hooks
这是因为回调函数并不是真正在构建方法中,它是在外部执行的。
The following Error was thrown building ExampleWidget(dirty, dependencies: [UncontrolledProviderScope]):
Instance of 'Error'
这是我前面提到的构建错误的一个例子post。
我会说你最好重构以将 StateProvider
设置为先前小部件中的文本,而不是接受文本作为参数并尝试设置它,但我认为以下方法可行使用您当前的方法,尽管我再次建议您以不同的方式解决您的问题。
class ExampleWidget extends HookWidget {
const ExampleWidget({required String text});
final String text;
@override
Widget build(BuildContext context) {
final future = useMemoized(() => Future<void>.delayed(const Duration(milliseconds: 1)));
final snapshot = useFuture<void>(future, initialData: null);
if (snapshot.connectionState == ConnectionState.done) {
context.read(stateProvider).state = text;
}
return Column(
children: [
Text(useProvider(stateProvider).state),
Container(
child: ChildWidget(),
),
],
);
}
}
通过将状态更改延迟到初始构建之后,我们可以避免构建错误。
基本上,我想将初始构造函数值设置为 StateProvider
,以便我可以在其子部件中使用它。
final stateProvider = StateProvider((ref) => "default");
class ExampleWidget extends ConsumerWidget {
ExampleWidget({required String text}){
// how to override default hear as
// stateProvider = text
}
@override
Widget build(BuildContext context, ScopedReader watch) {
return Column(
children: [
Text(watch(stateProvider).state),
Container(
child: ChildWidget(),
),
],
);
}
}
class ChildWidget extends ConsumerWidget {
@override
Widget build(BuildContext context, ScopedReader watch) {
return Container(
child: Text(watch(stateProvider).state),
);
}
}
那么我该如何实现呢?
我试过this但是状态值没有更新。
编辑----------------
与riverpod_hook
& hooks_flutter
final stateProvider = StateProvider((ref) => "default");
class ExampleWidget extends HookWidget {
@override
Widget build(BuildContext context) {
WidgetsBinding.instance?.addPostFrameCallback((_) {
useEffect((){
context.read(stateProvider).state = "new value";
},[]);
});
final state = useProvider(stateProvider).state;
return Column(
children: [
Text(state),
],
);
}
}
上面的代码抛出了这个错误
Hooks can only be called from the build method of a widget that mix-in
挂钩``
所以我尝试在build方法下初始化是这样的
useEffect((){
context.read(stateProvider).state = "new value";
},[]);
但上面的代码抛出以下错误:
The following Error was thrown building ExampleWidget(dirty, dependencies: [UncontrolledProviderScope]):
Instance of 'Error'
我只想初始化一次值,这就是为什么我想使用 useEffect
钩子。
您无法在构造函数中正常访问提供程序。您也不应该直接在构建方法中更新状态,因为这可能会导致构建错误(在您设置会导致另一次重建的状态之前小部件尚未完成构建)。
您应该可以使用 addPostFrameCallback
在构建小部件后更改状态。
例如:
class ExampleWidget extends ConsumerWidget {
const ExampleWidget({required String text});
final String text;
@override
Widget build(BuildContext context, ScopedReader watch) {
WidgetsBinding.instance?.addPostFrameCallback((_) {
context.read(stateProvider).state = text;
});
return Column(
children: [
Text(watch(stateProvider).state),
Container(
child: ChildWidget(),
),
],
);
}
}
关于您的编辑:
Hooks can only be called from the build method of a widget that mix-in Hooks
这是因为回调函数并不是真正在构建方法中,它是在外部执行的。
The following Error was thrown building ExampleWidget(dirty, dependencies: [UncontrolledProviderScope]):
Instance of 'Error'
这是我前面提到的构建错误的一个例子post。
我会说你最好重构以将 StateProvider
设置为先前小部件中的文本,而不是接受文本作为参数并尝试设置它,但我认为以下方法可行使用您当前的方法,尽管我再次建议您以不同的方式解决您的问题。
class ExampleWidget extends HookWidget {
const ExampleWidget({required String text});
final String text;
@override
Widget build(BuildContext context) {
final future = useMemoized(() => Future<void>.delayed(const Duration(milliseconds: 1)));
final snapshot = useFuture<void>(future, initialData: null);
if (snapshot.connectionState == ConnectionState.done) {
context.read(stateProvider).state = text;
}
return Column(
children: [
Text(useProvider(stateProvider).state),
Container(
child: ChildWidget(),
),
],
);
}
}
通过将状态更改延迟到初始构建之后,我们可以避免构建错误。