RouterModule.forRoot (ROUTES) vs RouterModule.forChild (RUTAS)


¿Cuáles son las diferencias entre estos dos y cuáles son los casos de uso para cada uno?

Los documentos no son exactamente útiles:

ForRoot crea un módulo que contiene todas las directivas, las rutas, y el propio servicio del router.

ForChild crea un módulo que contiene todas las directivas y las rutas dadas, pero no incluye el servicio del router.

Mi vaga suposición es que uno es para el módulo 'principal' y el otro es para cualquier módulo importado (ya que ya tendrían el servicio disponible desde el módulo principal), pero realmente no puedo pensar en un caso de uso.

Author: jonrsharpe, 2016-11-09

4 answers

Le sugiero encarecidamente que lea este artículo:

Módulo con proveedores

Cuando importa un módulo, normalmente utiliza una referencia a la clase module: {[15]]}

@NgModule({
    providers: [AService]
})
export class A {}

-----------------------------------

@NgModule({
    imports: [A]
})
export class B

De esta manera, todos los proveedores registrados en el módulo A se agregarán al inyector raíz y estarán disponibles para toda la aplicación.

Pero hay otra manera de registrar un módulo con proveedores como esto:

@NgModule({
    providers: [AService]
})
class A {}

export const moduleWithProviders = {
    ngModule: A,
    providers: [AService]
};

----------------------

@NgModule({
    imports: [moduleWithProviders]
})
export class B

Esto tiene las mismas implicaciones que el anterior.

Probablemente sepas que los módulos lazy loaded tienen su propio inyector. Así que supongamos que desea registrar AService para estar disponible para toda la aplicación, pero algunos BService para estar disponibles solo para módulos cargados perezosamente. Puedes refactorizar tu módulo así:

@NgModule({
    providers: [AService]
})
class A {}

export const moduleWithProvidersForRoot = {
    ngModule: A,
    providers: [AService]
};

export const moduleWithProvidersForChild = {
    ngModule: A,
    providers: [BService]
};

------------------------------------------

@NgModule({
    imports: [moduleWithProvidersForRoot]
})
export class B

// lazy loaded module    
@NgModule({
    imports: [moduleWithProvidersForChild]
})
export class C

Ahora BService sólo estará disponible para el niño perezoso módulos cargados y AService estará disponible para toda la aplicación.

Usted puede reescribir lo anterior como un módulo exportado como este:

@NgModule({
    providers: [AService]
})
class A {
    forRoot() {
        return {
            ngModule: A,
            providers: [AService]
        }
    }

    forChild() {
        return {
            ngModule: A,
            providers: [BService]
        }
    }
}

--------------------------------------

@NgModule({
    imports: [A.forRoot()]
})
export class B

// lazy loaded module
@NgModule({
    imports: [A.forChild()]
})
export class C

¿Cómo es eso relevante para RouterModule?

Supongamos que se accede a ambos usando el mismo token:

export const moduleWithProvidersForRoot = {
    ngModule: A,
    providers: [{provide: token, useClass: AService}]
};

export const moduleWithProvidersForChild = {
    ngModule: A,
    providers: [{provide: token, useClass: BService}]
};

Con configuraciones separadas cuando se solicita token desde un módulo de carga lenta, se obtiene BService tal como se planeó.

RouterModule usa ROUTES token para obtener todas las rutas específicas de un módulo. Puesto que quiere que las rutas específicas del módulo lazy loaded estén disponibles dentro de este módulo (análogos para nuestro BService) utiliza diferentes confirmaciones para los módulos hijo lazy loaded:

static forChild(routes: Routes): ModuleWithProviders {
    return {
        ngModule: RouterModule, 
        providers: [{provide: ROUTES, multi: true, useValue: routes}}]
    }
}
 61
Author: Max Wizard K,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-31 05:26:24

La documentación establece claramente cuál es el propósito de esta distinción aquí: https://angular.io/docs/ts/latest/guide/ngmodule.html#! # core-for-root

Llame a forRoot solo en el módulo de aplicación raíz, AppModule. Llamarlo en cualquier otro módulo, particularmente en un módulo cargado perezosamente, es contrario a la intent y es probable que produzca un error de tiempo de ejecución.

Recuerde importar el resultado; no lo agregue a ninguna otra lista @NgModule.

Cada la aplicación tiene exactamente un punto de partida (raíz) donde el servicio de enrutamiento principal debe inicializarse con forRoot, mientras que las rutas para características "secundarias" particulares deben registrarse adicionalmente con forChild. Es extremadamente útil para submódulos y módulos cargados perezosos que no tienen que cargarse al inicio de la aplicación, y como dijo @Harry Ninh, se les dice que reutilicen RouterService en lugar de registrar el nuevo servicio, lo que puede causar un error de tiempo de ejecución.

 16
Author: Marcin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-09 16:01:45

Creo que las respuestas son correctas, pero creo que falta algo.
Lo que falta es " ¿por qué y qué resuelve ?".
Ok, empecemos.

Primero mencionemos algo de información:

Todos los módulos tienen acceso a los servicios raíz.
Así que incluso los módulos cargados perezosos pueden usar un servicio que se proporcionó en app.module.
¿Qué pasará si un módulo lazy loaded se proporciona a sí mismo un servicio que el módulo app ya proporcionó ? habrá 2 instancia.
No es un problema pero a veces lo es.
¿Cómo podemos resolverlo ? simplemente no importe un módulo con ese proveedor a módulos cargados perezosamente.

Fin de la historia.

Esto ^ fue solo para mostrar que los módulos lazy loaded tienen su propio punto de inyección ( a diferencia de los módulos no lazy-loaded).

Pero, ¿qué sucede cuando un compartido(!) module has declared providers, and that module is imported by lazy and app.module ? Nuevo , como dijimos , dos casos.

Entonces, ¿cómo podemos resolver esto en el módulo compartido POV ? ¡necesitamos una manera no de usar providers:[]! ¿Por qué? debido a que se importarán automáticamente tanto al consumo perezoso como a la aplicación.módulo y no queremos que como vimos que cada uno tendrá una instancia diferente.

Bueno, resulta que podemos declarar un módulo compartido que no tendrá providers:[], pero aún así, proporcionará prodivers (lo sentimos :))

¿Cómo ? Así :

introduzca la descripción de la imagen aquí

Aviso , no hay proveedores.

Pero

  • Lo que sucederá ahora cuando la aplicación.módulo importará el módulo compartido con POV de servicio ? NADA.

  • ¿Qué pasará ahora cuando un módulo perezoso importará el módulo compartido con POV de servicio ? NADA.

Introducción del mecanismo manual mediante convención:

Usted notará que los proveedores en las imágenes tienen service1 y service2

Esto nos permite importar service2 para módulos lazy loaded y service1 para módulos no lazy. ( tos...router....tos)

Por cierto , nadie te impide llamar a forRoot dentro de un módulo perezoso. pero tendrá 2 instancias porque app.module también debería hacerlo - así que no lo haga en módulos perezosos.

También - si app.module llama forRoot ( y nadie llama forchild ) - eso está bien , pero root injector solo tendrá service1. (disponible para todas las aplicaciones)

So ¿por qué lo necesitamos ? Yo diría:

Permite un módulo compartido, para poder dividir su diferentes-proveedores para ser utilizados con módulos eager y módulos lazy - a través de los convenios forRoot y forChild. Repito : convención

Eso es.

ESPERA !! ¿ni una sola palabra sobre Singleton ?? entonces, ¿por qué leo ¿singleton por todas partes ?

Bueno, está oculto en la oración anterior ^

Permite un módulo compartido, para poder dividir su diferentes-proveedores para ser utilizados con módulos eager y módulos lazy - vía forRoot y forChild.

La convención (!!!) permite que sea singleton - o para ser más preciso - si no sigue la convención - NO obtendrá un singleton.
Así que si solo carga forRoot en el app.module, entonces solo obtiene una instancia porque solo debe llamar forRoot en el app.module.
Por cierto-en este punto puedes olvidarte de forChild. el módulo lazy loaded no debería / no llamará forRoot - por lo que está seguro en POV de singleton.

ForRoot y forChild no son un paquete irrompible - es solo que no tiene sentido llamar a Root que obviamente se cargará solo en app.module sin dar la capacidad para módulos perezosos , tener sus propios servicios , sin crear nuevos servicios-que-deberían-ser-singleton.

Presente convenio darle una buena habilidad llamada forChild - para consumir "servicios solo para módulos cargados perezosos".

Aquí está una demostración Los proveedores de raíz producen números positivos, los módulos cargados perezosos producen números negativos.

 8
Author: Royi Namir,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-13 12:00:42

Https://www.freelancermap.com/freelancer-tips/12255-forroot-forchild-angular

Este es un artículo sobre el uso de forRoot y forChild en Angular; No estoy particularmente versado en el tema, pero tal vez puede ser útil!

 -1
Author: user9807886,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-17 18:22:48