skip to Main Content

I’m having issues accessing my Map state to get the length of the list MartialArtsMove.hand.

Here is my class/provider:

import 'package:flutter_riverpod/flutter_riverpod.dart';

enum MartialArtsMove {
  hand,
  kick,
  grab;
}

class OneSteps extends Notifier<Map<MartialArtsMove, List<num>>> {
  @override
  Map<MartialArtsMove, List<num>> build() =>
      {for (final k in MartialArtsMove.values) k: <num>[]};

  void setMove(MartialArtsMove martialArtsMove, List<num> items) {
    state[martialArtsMove] = items;
    ref.notifyListeners();
  }

  void clearAll() {
    for (final martialArtsMove in MartialArtsMove.values) {
      state[martialArtsMove]!.clear();
    }
    ref.notifyListeners();
  }
}

final oneStepsProvider = StateProvider<OneSteps>((_) => OneSteps());

and here is how I use it on my page:

var oneStepState = ref.watch(oneStepsProvider);

Text(
                  'Hands ${oneStepState.state[MartialArtsMove.hand]!.length}',
                  textAlign: TextAlign.center,
                  // overflow: TextOverflow.ellipsis,
                  style: const TextStyle(fontSize: 14),
                )

I have also tried

Text(
                  'Hands ${oneStepState[MartialArtsMove.hand]!.length}',
                  textAlign: TextAlign.center,
                  // overflow: TextOverflow.ellipsis,
                  style: const TextStyle(fontSize: 14),
                )

2

Answers


  1. StateProvider is the right Provider for cases where you simply want to read and write values.

    For cases like the above, you can use a NotifierProvider to have a defined action (method) update the state.

    You can read more about this below.

    Login or Signup to reply.
  2. You’re creating a Notifier but then exposing it through a StateProvider. Those classes are not designed to work together, and in fact the code you shared contains a linter warning that you shouldn’t access Notifier.state from outside the class. The simplest fix is to change your provider type to NotifierProvider and update your ref usage to retrieve the notifier and its state separately:

    typedef OneStepsState = Map<MartialArtsMove, List<num>>;
    
    class OneSteps extends Notifier<OneStepsState> {
        // Unmodified, cut for brevity
    }
    
    final oneStepsProvider =
        NotifierProvider<OneSteps, OneStepsState>(() => OneSteps());
    
    // Example of how to access the state and react to changes
    class HandsText extends ConsumerWidget {
      @override
      Widget build(BuildContext context, ref) {
        final oneStepState = ref.watch(oneStepsProvider);
        final len = oneStepState[MartialArtsMove.hand]!.length;
    
        return Text('Hands $len');
      }
    }
    
    
    // Example of how to call the notifier methods
    class ClearOneStepsButton extends ConsumerWidget {
      @override
      Widget build(context, ref) {
        return IconButton(
          onPressed: () {
            ref.read(oneStepsProvider.notifier).clearAll();
          },
          icon: const Icon(Icons.refresh),
        );
      }
    }
    

    Here’s a working Dartpad demonstrating the changes + some other misc refactoring like making the state immutable, which is a bit more idiomatic in Riverpod.

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