modular icon indicating copy to clipboard operation
modular copied to clipboard

Migração de Modular v5 para v6

Open adrinebt opened this issue 10 months ago • 14 comments

Tenho o seguinte código, como poderia migrar para a v6?

Tenho LoginModule que está dentro de app/modules/login

class LoginModule extends Module {
  @override
  final List<Bind> binds = [
    Bind.lazySingleton((i) => LoginController(
        i<IUsuarioService>(),
        i<IConfiguracaoAppService>(),
        i.get<LoginRepository>(),
        i.get<UsuarioModel>(),
    ),
    ),
    Bind.lazySingleton((i) => LoginRepository()),
    Bind.lazySingleton((i) => UsuarioModel())
  ];

  @override
  final List<ModularRoute> routes = [
    ChildRoute(Modular.initialRoute, child: (_, args) => const LoginPage()),
  ];
}

Tenho AppModule que contém todos os módulos

@override
  final List<ModularRoute> routes = [
    ModuleRoute(Modular.initialRoute, module: SplashModule()),
    ModuleRoute('/login', module: LoginModule()),
];

adrinebt avatar Apr 22 '24 17:04 adrinebt

Olá @adrinebt,

Veja essa parte da documentação com a comparação: https://modular.flutterando.com.br/docs/flutter_modular/migration-5-to-6

eduardoflorence avatar Apr 23 '24 12:04 eduardoflorence

Minha dúvida é sobre como lidar com o caso do construtor de LoginController que tem as dependências IUsuarioService, IConfiguracaoAppService como funcionaria na migração não encontrei nada parecido na documentação

@override
  final List<Bind> binds = [
    Bind.lazySingleton((i) => LoginController(
        i.get<IUsuarioService>(),
        i.get<IConfiguracaoAppService>(),
        i.get<LoginRepository>(),
        i.get<UsuarioModel>(),
    ),
    ),
    Bind.lazySingleton((i) => LoginRepository()),
    Bind.lazySingleton((i) => UsuarioModel())
  ];

adrinebt avatar Apr 23 '24 13:04 adrinebt

IUsuarioService e IConfiguracaoAppService estão no binds de outro Módulo? Se sim, pode mostrar o nome desse outro módulo e a parte do binds dele para eu te dar um exemplo correto?

eduardoflorence avatar Apr 24 '24 12:04 eduardoflorence

Outro exemplo é no módulo do Splash que vem antes do login que mostrei anteriormente

class SplashModule extends Module {
  @override
  final List<Bind> binds = [
    Bind.lazySingleton((i) => SplashController()),
    Bind.lazySingleton((i) => LoginController(
        i.get<IUsuarioService>(),
        i.get<IConfiguracaoAppService>(),
        i.get<LoginRepository>(),
        i.get<UsuarioModel>(),
  ),
    ),
  ];

  @override
  final List<ModularRoute> routes = [
    ChildRoute(Modular.initialRoute, child: (_, args) => const SplashPage()),
  ];
}

adrinebt avatar Apr 24 '24 13:04 adrinebt

Para te dar o exemplo na versão 6 corretamente, eu precisaria saber onde são declaradas as dependências IUsuarioService e IConfiguracaoAppService. Elas estão no binds seu AppModule ou num SharedModule? Ou elas estão no binds do LoginModule e SplashModule, só que você cortou ao colocar o código nos exemplos acima?

Ou seja, no LoginModule e SplashModule, que mostrou acima, você obtém essas dependências (IUsuarioService e IConfiguracaoAppService), mas em algum módulo anterior você colocou essas dependências no binds para serem usadas posteriormente.

eduardoflorence avatar Apr 24 '24 14:04 eduardoflorence

IUsuarioService e IConfiguracaoAppService são dependências de LoginController e declaradas em LoginModule. este por sua vez é declarado no AppModule como no código abaixo

@override
  final List<ModularRoute> routes = [
    ModuleRoute(Modular.initialRoute, module: SplashModule()),
    ModuleRoute(routeLogin, module: LoginModule()),
    ModuleRoute(routeHome, module: HomeModule()),
    ModuleRoute(routeConsulta, module: ConsultaModule()),
  ];

adrinebt avatar Apr 24 '24 15:04 adrinebt

Ok, acredito que não tenha você não compreendeu a informação que preciso, mas vou te dar um exemplo de como eu faria na versão 6 do Modular:

  • Como IUsuarioService e IConfiguracaoAppService serão usados em mais de um módulo, o ideal é colocá-los num módulo à parte com exportação. Vou supor que IUsuarioService e IConfiguracaoAppService são interfaces e UsuarioServiceImpl e ConfiguracaoAppServiceImpl são as implementações destas interfaces. Faça um CoreModule desta forma:
class CoreModule extends Module {
  @override
  void exportedBinds(Injector i) {
    i.addSingleton<IUsuarioService>(UsuarioServiceImpl.new);
    i.addSingleton<IConfiguracaoAppService>(ConfiguracaoAppServiceImpl.new);
  }
}
  • Seu LoginModule, importará CoreModule e ficará então desta forma:
class LoginModule extends Module {
  @override
  List<Module> get imports => [CoreModule()];

  @override
  void binds(Injector i) {
    i.addLazySingleton(LoginController.new),
    i.addLazySingleton(LoginRepository.new),
    i.addLazySingleton(UsuarioModel.new)
  } 

  @override
  void routes(RouteManager r) {
    r.child(Modular.initialRoute, child: (context) => const LoginPage()),
  }
}

Ao fazer LoginController.new o sistema de injeção de dependências fará a injeção automática de cada dependência que LoginController precisa via construtor, basta que exista um bind dessas dependências, que foi o que fiz nos exemplos acima.

eduardoflorence avatar Apr 24 '24 16:04 eduardoflorence

Perdão, não sei se essa era a sua dúvida agora creio que compreendi. IUSuarioService e IConfiguracaoAppService são de fato interfaces implementadas respectivamente em UsuarioService e ConfiguracaoAppService que como no código abaixo estão declaradas nos binds do AppModule

@override
  final List<Bind> binds = [
    Bind.lazySingleton((i) => ConfiguracaoAppService()),
    Bind.lazySingleton((i) => UsuarioService(i<IUsuarioRepository>())),
    Bind.lazySingleton((i) => CustomDio(i<BaseOptions>())),
    Bind(
      (i) => BaseOptions(
        baseUrl: baseUrlNova,
        contentType: Headers.formUrlEncodedContentType,
        connectTimeout: const Duration(seconds: 90),
        receiveTimeout: const Duration(seconds: 90),
        sendTimeout: const Duration(seconds: 90),
        receiveDataWhenStatusError: true,
      ),
    ),
  ];

adrinebt avatar Apr 24 '24 17:04 adrinebt

Isso mesmo que eu estava querendo saber. Esse Bind que mostrou agora por último ficará assim:

class CoreModule extends Module {
  @override
  void exportedBinds(Injector i) {
    i.addLazySingleton<IConfiguracaoAppService>(ConfiguracaoAppService.new);
    i.addLazySingleton<IUsuarioService>(UsuarioService.new);
    i.addLazySingleton<CustomDio>(CustomDio.new), 
    i.addInstance<BaseOptions>(
      () => BaseOptions(
        baseUrl: baseUrlNova,
        contentType: Headers.formUrlEncodedContentType,
        connectTimeout: const Duration(seconds: 90),
        receiveTimeout: const Duration(seconds: 90),
        sendTimeout: const Duration(seconds: 90),
        receiveDataWhenStatusError: true,
      ),
    ),
  }
}

Em cada módulo que precisar do IConfiguracaoAppService e IUsuarioService, você precisará importar este CoreModule como mostrei no exemplo anterior em LoginModule. Essa é a orientação no Modular 6 (No 5 não precisava)

eduardoflorence avatar Apr 24 '24 18:04 eduardoflorence

Obs.: Não use o AppModule para fazer esse exportedBinds das dependências que serão compartilhadas, use um módulo em separado (orientação para modular 6) como o CoreModule do meu exemplo. Se até o AppModule precisar das dependências, pode importar também.

eduardoflorence avatar Apr 24 '24 18:04 eduardoflorence

Interessante, não fiz a migração por conta disso, não havia entendido.

rodrigolmacedo avatar Apr 24 '24 18:04 rodrigolmacedo

nesse caso o AppModule serviria somente para declarar os modules como SplashModule, LoginModule?

adrinebt avatar Apr 24 '24 19:04 adrinebt

nesse caso o AppModule serviria somente para declarar os modules como SplashModule, LoginModule?

Sim, você até pode colocar bind nele, mas seria só de dependências que seriam usadas exclusivamente no AppModule, caso ele tivesse uma página inicial, antes de ir para outro módulo, por exemplo. Obs.: Você consegue acessar um bind do AppModule em qualquer outro módulo declarado por ele, fazendo Modular.get<SuaDependencia>(), mas isso não é aconselhável, pois "estraga" a sua arquitetura, já que seria por fora da injeção de dependências.

eduardoflorence avatar Apr 24 '24 19:04 eduardoflorence