rrousselGit / state_notifier

ValueNotifier, but outside Flutter and with some extra perks
MIT License
311 stars 28 forks source link

LocatorMixin throw Exception when read, but Provider.of(context) work fine #28

Closed tbm98 closed 4 years ago

tbm98 commented 4 years ago

when I call read<>() it throw Exception

Unhandled Exception: Instance of 'DependencyNotFoundException<RootState>'
#0      new _ChangePasswordStateNotifier&Object&EventMixin&LocatorMixin.<anonymous closure>
class ChangePasswordStateNotifier with EventMixin, LocatorMixin {
  void submitUpdate(String fullName,
      String currentPassword, String newPassword) async {
    eventInput.add(EventEntry.loading());
    final token = read<RootState>().account.token;
    final result = await read<RestClient>()
        .changePassword(
            token: token,
            password: currentPassword,
            newPassword: newPassword,
            fullName: fullName);
    eventInput.add(EventEntry.pop());
    logs(result.toJson());
  }
}

but if I replace by Provider.of(context) it work fine

class ChangePasswordStateNotifier with EventMixin, LocatorMixin {
  void submitUpdate(BuildContext context, String fullName,
      String currentPassword, String newPassword) async {
    eventInput.add(EventEntry.loading());
    final token = Provider.of<RootState>(context, listen: false).account.token;
    final result = await Provider.of<RestClient>(context, listen: false)
        .changePassword(
            token: token,
            password: currentPassword,
            newPassword: newPassword,
            fullName: fullName);
    eventInput.add(EventEntry.pop());
    logs(result.toJson());
  }
}

where am i wrong ?

rrousselGit commented 4 years ago

It's likely that the BuildContext you passed to submitUpdate is lower in the tree than the one associated with the provider (that read uses)

tbm98 commented 4 years ago

I am declaring RootState andRestClient as the top of the tree.

void main() => runApp(
      MultiProvider(providers: [
        Provider<NavigatorStore>(
          create: (_) => NavigatorStore(),
          lazy: false,
        ),
        Provider(
          create: (_) => SharedPrefs(),
        ),
        Provider(
          create: (_) => RestClient.create(),
        ),
        StateNotifierProvider<RootStateNotifier, RootState>(
            create: (context) => RootStateNotifier())
      ], child: MyApp()),
    );

then I push to ChangePasswordPage

  void _openChangePassword() {
    context.push((_) => Provider<ChangePasswordHandler>(
        create: (_) => ChangePasswordHandler(),
        child: ChangePasswordPage()));
  }

and context I passed to submitUpdate is from ChangePasswordPage

Currently my ChangePasswordHandler does not inherit any other class, is it a problem?

tbm98 commented 4 years ago

I have just confirmed this. read only works inStateNotifierProvider, it does not work in Provider

rrousselGit commented 4 years ago

Yes that is expected

tbm98 commented 4 years ago

Oh. I think the document should warn this.