skip to Main Content

I’m learning flutter and I was wondering how the state management works. At the moment I have a form in which I want to preview a selected image, selected country or a loader when submitted.
Not sure if the approach is correct though. I feel like this kind of state management should be done differently. Please, let me know if it’s okay to use state management or if it’s not, how should I approach such cases.

// Define a loader for the user profile update
final isLoadingProvider = StateProvider<bool>((ref) => false);
final selectedCountryProvider = StateProvider<String?>((ref) => null);

Let me share only the widgets I’m using the states on.

  @override
  Widget build(BuildContext context, ref) {
    final isLoading = ref.watch(isLoadingProvider);
    final selectedCountry = ref.watch(selectedCountryProvider);
    ... next part of the code
// Inside column widget's childrens
if (isLoading) const CircularProgressIndicator(),
      TextFormField(
        initialValue: selectedCountry ?? userProfile.country,
        decoration: const InputDecoration(
          labelText: "Country",
          border: OutlineInputBorder(
              borderRadius: BorderRadius.all(Radius.circular(5)),
              borderSide: BorderSide(color: textColor)),
          hintText: 'Select a country'),
        onTap: () => showCountryPicker(
          context: context,
          showPhoneCode: false,
          onSelect: (Country value) {
            ref.read(selectedCountryProvider.notifier).state = value.name;
          },
        ),
      ),

2

Answers


  1. Riverpod suggests to avoid using providers for local widget state. If there are multiple widgets in the same widget tree that need to access the state, you can put the state in the topmost widget (make it a state variable of a StatefulWidget‘s State, or use useState from flutter_hooks) and pass down the state through parameters.

    If you really need shared state, then you can use Notifier instead, since StateProvider is now discouraged. The most basic example of using a Notifier for a shared state is shown in the homepage of Riverpod docs:

    // A shared state that can be accessed by multiple widgets at the same time.
    @riverpod
    class Count extends _$Count {
      @override
      int build() => 0;
    
      void increment() => state++;
    }
    
    // Consumes the shared state and rebuild when it changes
    class Title extends ConsumerWidget {
      @override
      Widget build(BuildContext context, WidgetRef ref) {
        final count = ref.watch(countProvider);
        return Text('$count');
      }
    }
    

    If you don’t want to use code generator, you can define the provider and the notifier like this:

    final counterProvider = NotifierProvider<Counter, int>(Counter.new);
    
    class Counter extends Notifier<int> {
      @override
      int build() => 0;
    
      void increment() => state++;
    }
    
    Login or Signup to reply.
  2. Form state should not be put inside providers.

    Form state is local to UI widgets and tightly coupled with navigation. For example, if you have a form that spans over multiple pages, if the user presses "back" at a step, this should likely reset currently visible fields.
    Or a user may quit a form, and re-enter it again later. Again, it probably would be unexpected to have the previous form state preserved.

    As such, using providers for form state is undesirable.

    The recommended solution is to use plain StatefulWidgets. Or if you wish to be fancy, use flutter_hooks, which is typically combined with Riverpod for animations or forms.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search