Flutter : Checking the type of Provider

Dr_Skele·2023년 3월 14일
0

Flutter

목록 보기
14/19

The provider can't be found and even if you're sure it should be there, check the widget inspector and see if the type of the provider is right.

To use the provider, type of the provider needs to be specific. Even if it's inherited from the parent class, the provider won't automatically find it.

abstract class A extends ChangeNotifier {
  get string;
}

class AB extends A {
  @override
  get string => 'AB';
}

class AC extends A {
  @override
  get string => 'AC';
}

Here's some inherited changenotifier classes.

class MyGenericProviderApp extends StatelessWidget {
  const MyGenericProviderApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(useMaterial3: true, primaryColor: Colors.red),
      home: GenericProvider(
        changeNotifier: AB(),
      ),
    );
  }
}

class GenericProvider extends StatelessWidget {
  const GenericProvider({super.key, required this.changeNotifier});

  final A changeNotifier;

  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider.value(
      value: changeNotifier,
      builder: (context, child) {
        return const ProviderConsumer();
      },
    );
  }
}

class ProviderConsumer extends StatelessWidget {
  const ProviderConsumer({super.key});

  @override
  Widget build(BuildContext context) {
    var provider = Provider.of<AB>(context);
    return Scaffold(
      body: Center(child: Text(provider.string)),
    );
  }
}

Above code will throw an error saying that the provider of AB can't be found.

ProviderNotFoundException (Error: Could not find the correct Provider<AB> above this ProviderConsumer Widget...)

The consumer cannot know if the Provider if of 'A' or 'AB' because it's given as 'A'. With the widget inspector, the problem can be seen.

The 'AB' changenotifier is provided as 'A'. This is why flutter can't find the right provider of type 'AB', because it isn't 'AB' but 'A'.

This problem can be solved easily with type casting.

var provider = Provider.of<A>(context) as AB;

First way is to cast the type of the provider to inherited class in the child widget. Downside of this solution is that the provider should be casted everytime it's called. It can mess up the code when using context.read or context.watch.

But I have an alternate solution that can avoid that problem.

class GenericProvider<T extends A> extends StatelessWidget {
  const GenericProvider({super.key, required this.changeNotifier});

  final T changeNotifier;

  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider.value(
      value: changeNotifier,
      builder: (context, child) {
        return const ProviderConsumer();
      },
    );
  }
}

Type casting is no longer needed if generic method is used.

Now, in the widget inspector, the provider is of type 'AB'.

Anyways, this mistake I've made with provider type has taught me some lessons. With generic expressions, I think I can solve some problems and also cleanup codes with various types.

profile
Tireless And Restless Debugging In Source : TARDIS

0개의 댓글