James
James

Reputation: 108

Flutter - How to use class-wide state with Riverpod?

I have a button that uses a counter provider with Riverpod, I would like to add a local state isLoading to the button.

While I can do it all inside the build method, I'm wondering if there is a way to lift the state to the instance level so that other methods inside the Btn class can also access this state, for instance, making onPressed function into another method.

The code with everything inside build:

class Btn extends HookConsumerWidget {
  const Btn({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final isLoading = useState(false);
    final counter = ref.watch(counterProvider);
    final counterNotifier = ref.read(counterProvider.notifier);
    useEffect(() {
      if (isLoading.value) {
        Future.delayed(const Duration(seconds: 1), () {
          isLoading.value = false;
          counterNotifier.reset();
        });
      }
      return null;
    }, [isLoading.value]);

    return ElevatedButton.icon(
      onPressed: () => isLoading.value = true : null,
      icon: isLoading.value ? const CircularProgressIndicator() : Container(),
      label:Text(isLoading.value ? "Loading" : "$counter"),
    );
  }
}

I would like to turn it into:

class Btn extends HookConsumerWidget {
  const Btn({super.key});

  // declare isLoading

  void onPressed() {
    isLoading.value = true;
  }

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final counter = ref.watch(counterProvider);
    final counterNotifier = ref.read(counterProvider.notifier);
    useEffect(() {
      if (isLoading.value) {
        Future.delayed(const Duration(seconds: 1), () {
          isLoading.value = false;
          counterNotifier.reset();
        });
      }
      return null;
    }, [isLoading.value]);

    return ElevatedButton.icon(
      onPressed: onPressed,
      icon: isLoading.value ? const CircularProgressIndicator() : Container(),
      label: Text(isLoading.value ? "Loading" : "$counter"),
    );
  }
}

Upvotes: 2

Views: 61

Answers (1)

Ruble
Ruble

Reputation: 4844

You can turn your class into a ConsumerStatefullWidget and discard the hooks, then all your parameters can become class fields.

Furthermore, try not to pull logic into the widget. There is business logic, then place it in a notifier class (and even use an AsyncNotifier that contains "sealed" state with data, load and error). If it's ui logic, it's not a bad option to place it in the presenter classes.

All of this will increase code reusability and allow each layer of your application to clearly fulfill its responsibilities.

Upvotes: 0

Related Questions