skip to Main Content

I’m facing this very weird and primitive issue, I’m trying to figure it out but not able to.

I’ve designed an abstract class in following manner

abstract class BaseStatelessWidget<T extends BaseStore> extends StatelessWidget
    with RouteAware {
  late final T childStore;

  BaseStatelessWidget({super.key});

  @override
  Widget build(BuildContext context) {
    childStore = getImplementedStore();
    return Provider(
      create: <T>(_) => childStore,
      builder: (ctx, __) {
        final store = Provider.of<T>(ctx, listen: false); // <== I'm getting error here for providerNotFound excepton
        store;
        return _BaseStatefulWidget<T>(
          builder: buildScreen,
        );
      },
    );
  }

  Widget buildScreen(BuildContext context);

  T getImplementedStore();
}

This is the way I’ve implemented the Above abstract class,

class Counter extends BaseStatelessWidget<CounterStore> {
  Counter({super.key});

  @override
  Widget buildScreen(BuildContext context) {
    return Scaffold(
      body: Container(
        color: AppColors.white,
        child: Column(
          children: [
            Observer(
              builder: (ctx) {
                return Text(
                  '${getStore<CounterStore>(ctx).counter} Times Clicked',
                );
              },
            )
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          getStore<CounterStore>(context).increment();
        },
        child: const Icon(Icons.add),
      ),
    );
  }

  @override
  CounterStore getImplementedStore() {
    return getIt<CounterStore>();
  }
}

T getStore<T extends BaseStore>(BuildContext context) {
  return Provider.of<T>(context, listen: false);
}

As soon as I call the Provider.of method to get the injected object, I’m getting the exception.
Can someone point out, if I’m missing anything here??

2

Answers


  1. Chosen as BEST ANSWER

    After thorough research, I've found a solution that could be helpful to others encountering a similar issue.

    The provider package offers two methods to create a provider:

    • Using the Provider(create: (context) => TExtends())
    • Utilizing Provider.value(value: TExtends()).

    It's important to note that the first approach lacks abstraction support. Attempting to access T directly from the context will result in an exception. This is because the provided object will represent the implementation of T, rather than T itself.

    If your objective is to obtain an instance of T instead of TExtends, I recommend opting for the second method. This will allow you to resolve the issue.

    Here's an example implementation:

    abstract class BaseStatelessWidget<T extends BaseStore> extends StatelessWidget
        with RouteAware {
      late final T childStore;
    
      BaseStatelessWidget({super.key});
    
      @override
      Widget build(BuildContext context) {
        childStore = getImplementedStore();
        return Provider<T>.value( // <== This will solve the issue
          value: childStore,
          builder: (ctx, __) {
            final store = Provider.of<T>(ctx, listen: false); // You'll get instance of T, instead of childStore's instance
            store;
            return _BaseStatefulWidget<T>(
              builder: buildScreen,
            );
          },
        );
      }
    
      Widget buildScreen(BuildContext context);
    
      T getImplementedStore();
    }
    

  2. When declaring the provider, drop the return type in the create function:

        abstract class BaseStatelessWidget<T extends BaseStore> extends StatelessWidget with RouteAware {
      late final T childStore;
    
      BaseStatelessWidget({super.key});
    
      @override
      Widget build(BuildContext context) {
        childStore = getImplementedStore();
        return Provider(
          create: (_) => childStore,//Drop the return type
          builder: (ctx, __) {
            final store = Provider.of<T>(ctx, listen: false);
            return Text(store.value());
          },
        );
      }
    
      T getImplementedStore();
    }
    

    Tried the same and was able to get the provider’s value as expected.

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