modular icon indicating copy to clipboard operation
modular copied to clipboard

Export de binds na v6 do flutter_modular

Open darcanj0 opened this issue 2 years ago • 7 comments

Ambiente

  flutter_modular: ^6.3.2
  mobx: ^2.2.1
  flutter_mobx: ^2.1.1

Descrição Estou com dificuldades para conseguir compartilhar uma classe de Store feita com Mobx entre dois módulos da minha aplicação.

Tenho um Store de Autenticação (AuthStore) definido no meu AuthModule. Ele tem essa estrutura de dependências:

AuthStore -> AuthService -> ApiService

Ou seja, ele depende de um AuthService, que por sua vez, depende de um ApiService

No meu AuthModule, todas essas três classes já estão listadas dentro dos binds como Singletons, de tal forma que consigo usar meu AuthStore normalmente dentro do AuthModule.

class AuthModule extends Module {
  @override
  void binds(Injector i) {
    i.addSingleton<IApiService>(() => IApiService());
    i.addSingleton<IAuthService>(() => IAuthService());
    i.addSingleton(() => AuthStore.instance);
  }

  @override
  void exportedBinds(Injector i) {
    i.get<IApiService>();
    i.get<IAuthService>();
    i.get<AuthStore>();
  }
}

Tenho a necessidade de usar esse store dentro de um HomeModule. Tanto AuthModule, quanto HomeModule já estão registrados como módulos no AppModule. Também, já importei o AuthModule para dentro do meu HomeModule.

O problema está sendo em descobrir qual método do injetor eu uso, para registrar esse store, para ser exportado dentro do AuthModule. Quando uso qualquer um dos métodos i.add.. do injetor, recebo um erro apontando que a classe já existe no injetor. Por outro lado, quando uso algum método i.get , ele diz que a instância que é pedida no get não está registrada.

Qual a maneira correta de realizar esse export?

Além disso, há outro problema: Tem um momento da minha aplicação, em que eu saio do AuthModule, para navegar para o HomeModule. Nesse processo, o AuthModule está sendo encerrado, fazendo com que eu perca dados desse AuthStore, que eu gostaria de compartilhar. Minha ideia inicial era de ter dentro desse store um stream, para que eu pudesse controlar o estado de autenticação de um usuário no meu app.

Essa é uma decisão correta? Uma vez que eu conseguir exportar meu store, para ser usado em outro módulo, como posso prevenir que meu AuthModule (e consequentemente meu store) não seja encerrado?

Comportamento esperado Necessitava que um store fosse compartilhado entre dois módulos, bem como suas dependências

Código

Exemplo de um Singleton

abstract class IAuthService {
  Future<void> login(LoginDto dto);
  Future<void> signup();
  Future<void> signupWithGoogle();
  Future<void> signupWithLinkedin();
  Future<void> signout();
  Stream<CurrentUser?> get userChanges;

  factory IAuthService() => AuthMockService.instance;
}

O AuthStore mencionado

class AuthStore extends _AuthStore with _$AuthStore {
  AuthStore._({required super.authService});

  static AuthStore get instance =>
      AuthStore._(authService: Modular.get<IAuthService>());
}

abstract class _AuthStore with Store {
  final IAuthService service;

  @observable
  ObservableStream<CurrentUser?> userChanges;

  @action
  Future<void> signup() async {
    await service.signup();
  }

  _AuthStore({required IAuthService authService})
      : service = authService,
        userChanges = ObservableStream<CurrentUser?>(
          authService.userChanges,
          initialValue: null,
        );
}

darcanj0 avatar Nov 18 '23 19:11 darcanj0

Olá @darcanj0, O comentário abaixo vai ajudar você: https://github.com/Flutterando/modular/issues/914#issuecomment-1807200231

eduardoflorence avatar Nov 21 '23 12:11 eduardoflorence

Eu estou um pouco confuso nessa atualização. Pq n deixar a gente criar binds no module principal que possa ser usado em todo o app? @jacobaraujo7

railsonsm avatar Jan 03 '24 03:01 railsonsm

Estou passando pelo mesmo problema

danilocarreiro avatar Mar 18 '24 18:03 danilocarreiro

@railsonsm e @danilocarreiro, se o bind foi criado no módulo principal, você pode usar em todo o App, basta usar Modular.get<SeuBind>().

O que não pode ser feito é você recuperar automaticamente na área de binds de outro módulo para injetar como dependência em outro Bind, pois nesse caso precisa exportar num módulo "Core" e importar nos módulos que precisa.

eduardoflorence avatar Mar 19 '24 13:03 eduardoflorence

Opa @eduardoflorence era justamente isso q eu estava tentando fazer.

Eu tenho esses binds do meu AppModule

image

Ai eu estava tentando usar eles ali no meu UsuarioService que só funcionou injetando o AppModule no meu outro modulo.

image

Acredito q nesse caso seria interessante criar apenas um modulo com Binds que eu queira usar em outros lugares, correto? Como fazemos no angular

railsonsm avatar Mar 19 '24 14:03 railsonsm

Exatamente @railsonsm Eu costumo fazer um CoreModule com os binds que desejo compartilhar e injeto no AppModule e nos outros módulos que preciso desses binds. Nesse CoreModule você utiliza o exportedBinds assim, por exemplo:

class CoreModule extends Module {
  @override
  void exportedBinds(i) {
    i.addSingleton<UserDataSource>(UsesDataSourceImpl.new);
    i.addSingleton<UserRepository>(UserRepositoryImpl.new);
  }
}

eduardoflorence avatar Mar 19 '24 15:03 eduardoflorence

Show @eduardoflorence, muito bom! Tmj!

railsonsm avatar Mar 19 '24 15:03 railsonsm