How to initialize stateProvider from constructor in RiverPod

Issue

Basically, I want to set the initial constructor value to StateProvider so I can use it in its child widgets.

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),
    );
  }
}

So how do I implement this?

I have tried this but the state value is not updating.

Edit —————-

With 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),
      ],
    );
  }
}

above code throwing this error

Hooks can only be called from the build method of a widget that mix-in Hooks“

So I tried to initialize under the build method like this

useEffect((){
   context.read(stateProvider).state = "new value";
},[]);

but above code throws the following error:

The following Error was thrown building ExampleWidget(dirty, dependencies: [UncontrolledProviderScope]):
Instance of 'Error'

I just want to initialize the value once that’s why I want to use useEffect hook.

Solution

You can’t access providers in the constructor normally. You also shouldn’t update the state directly in the build method, as this can cause build errors (the widget hasn’t finished building before you set a state which would cause another rebuild).

You should be able to use addPostFrameCallback to change the state after the widget has built.

For example:

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(),
        ),
      ],
    );
  }
}

Regarding your edits:

Hooks can only be called from the build method of a widget that mix-in Hooks

This is because the callback function is not really in the build method, it’s executed externally.

The following Error was thrown building ExampleWidget(dirty, dependencies: [UncontrolledProviderScope]):
Instance of 'Error'

This is an example of the build errors I mentioned earlier in this post.

I would say you’re better off refactoring to just set the StateProvider to the text in a prior widget rather than accepting text as a parameter and trying to set it, but I think the following would work with your current approach, though again I’d recommend approaching your problem differently.

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(),
        ),
      ],
    );
  }
}

By delaying the state change until after the initial build we avoid build errors.

Answered By – Alex Hartford

Answer Checked By – Robin (FlutterFixes Admin)

Leave a Reply

Your email address will not be published.