RouterModule.forRoot (ROUTES) vs RouterModule.forChild (маршруты)
Каковы различия между этими двумя и каковы варианты использования для каждого из них?
ForRoot создает модуль, содержащий все директивы, заданные
маршруты и сама служба маршрутизатора.
ForChild создает модуль, который
содержит все директивы и заданные маршруты, но не включает в себя
служба маршрутизаторов.
Мое смутное предположение состоит в том, что один из них предназначен для "основного" модуля, а другой это для любых импортированных модулей (так как у них уже была бы служба, доступная из основного модуля), но я не могу действительно придумать вариант использования.
4 ответов:
Я настоятельно рекомендую прочитать эту статью:
Модуль с провайдерами
При импорте модуля обычно используется ссылка на класс модуля:
@NgModule({ providers: [AService] }) export class A {} ----------------------------------- @NgModule({ imports: [A] }) export class BТаким образом, все поставщики, зарегистрированные в модуле
A, будут добавлены в корневой инжектор и доступны для всего приложения.Но есть и другой способ зарегистрировать модуль у провайдеров, таких как это:
Это имеет те же последствия, что и предыдущее.@NgModule({ providers: [AService] }) class A {} export const moduleWithProviders = { ngModule: A, providers: [AService] }; ---------------------- @NgModule({ imports: [moduleWithProviders] }) export class BВы, вероятно, знаете, что ленивые загруженные модули имеют свой собственный инжектор. Поэтому предположим, что вы хотите зарегистрировать
AService, чтобы он был доступен для всего приложения, но некоторыеBServiceбудут доступны только для лениво загруженных модулей. Вы можете выполнить рефакторинг модуля такой:@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Теперь
BServiceбудет доступен только для дочерних лениво загруженных модулей, аAServiceбудет доступен для всего приложения.Ты можно переписать выше как экспортированный модуль следующим образом:
@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Какое это имеет отношение к RouterModule?
Предположим, что они оба доступны с помощью одного и того же маркера:
export const moduleWithProvidersForRoot = { ngModule: A, providers: [{provide: token, useClass: AService}] }; export const moduleWithProvidersForChild = { ngModule: A, providers: [{provide: token, useClass: BService}] };С отдельными конфигурациями при запросе
tokenиз лениво загруженного модуля вы получитеBServiceточно так же, как и планировалось.RouterModule использует маркер
ROUTESДля получения всех маршрутов, специфичных для модуля. Поскольку он хочет, чтобы маршруты, специфичные для лениво загруженного модуля, были доступны внутри этого модуля (аналоги нашему BService) он использует разные подтверждения для дочерних лениво загруженных модулей:static forChild(routes: Routes): ModuleWithProviders { return { ngModule: RouterModule, providers: [{provide: ROUTES, multi: true, useValue: routes}}] } }
В документации четко указано, какова цель этого различия здесь: https://angular.io/docs/ts/latest/guide/ngmodule.html#! # ядро для корня
ForRoot назвать только в корневой модуль приложения, модуль. Вызов его в любом другом модуле, особенно в лениво загруженном модуле, противоречит намерению и, скорее всего, приведет к ошибке во время выполнения.
Не забудьте импортировать результат; не добавляйте его в любой другой список @NgModule.
Каждый приложение имеет ровно одну начальную точку (root), где основная служба маршрутизации должна быть инициализирована с помощью
forRoot, в то время как маршруты для конкретных "дочерних" функций должны быть дополнительно зарегистрированы с помощьюforChild. Это чрезвычайно полезно для подмодулей и лениво загруженных модулей, которые не должны загружаться при запуске приложения, и, как сказал @Harry Ninh, им говорят, чтобы повторно использовать RouterService вместо регистрации нового сервиса, что может вызвать ошибку времени выполнения.
Я думаю, что ответы верны, но я думаю, что чего-то не хватает.
Чего не хватает, так это "почему и что она решает ?".
Ладно, начнем.Сначала давайте упомянем некоторую информацию:
Все модули имеют доступ к корневым службам.
Таким образом, даже лениво загруженные модули могут использовать сервис, который был предоставлен вapp.module.
Что произойдет, если лениво загруженный модуль предоставит себе услугу, которую уже предоставил модуль приложения ? будет 2 экземпляры.
Это не проблема , но иногда это так.
Как мы можем решить эту проблему ? просто не импортируйте модуль с этим поставщиком в лениво загруженные модули.Конец истории.
Это было просто, чтобы показать, что ленивые загруженные модули имеют свою собственную точку впрыска (в отличие от неленивых загруженных модулей).
Но что происходит, когда совместно (!) модуль объявил
providers, и этот модуль импортируется lazy иapp.module? Снова , как мы уже сказали, два случая.Итак, как мы можем решить эту проблему в общем модуле POV ? нам нужен способ не использовать
providers:[]! Почему? потому что они будут автоматически импортированы как в потребляющие lazy, так и в приложение.модуль и мы не хотим этого, так как мы видели, что у каждого будет свой экземпляр.Ну, получается, что мы можем объявить общий модуль, который не будет иметь
providers:[], но все же, предоставит prodivers (извините :))Как ? Подобный этому :
Обратите внимание, никаких поставщиков.
Но
Что будет теперь, когда приложение.модуль будет импортировать общий модуль с POV сервиса ? НИЧЕГО.
Что произойдет теперь, когда ленивый модуль импортирует общий модуль с POV сервиса ? НИЧЕГО.
Ввод ручного механизма через соглашение:
Вы заметите, что поставщики на картинках имеют
service1иservice2Это позволяет нам импортировать
service2для ленивых загруженных модулей иservice1для не-ленивых модулей. ([37]}кашель...обращать в бегство....кашель )Кстати , никто не мешает вам позвонить
forRootв ленивый модуль. но у вас будет 2 экземпляра, потому чтоapp.moduleтакже должен это сделать - так что не делайте это в ленивых модулях.Также-если
app.moduleвызываетforRoot(и никто не вызываетforchild) - это нормально , но корневой инжектор будет иметь толькоservice1. (доступно для всех приложений)Итак зачем нам это нужно ? Я бы сказал:
Это позволяет совместно используемому модулю, чтобы иметь возможность разделить его различные провайдеры, которые будут использоваться с нетерпеливыми модулями и ленивыми модулями - через
forRootиforChildконвенцию. Повторяю: конвенцияВот и все.
Подождите !!Ни единого слова о синглтоне ?? так почему же я читаю синглтон повсюду ?
Ну-это скрыто в предложении выше ^
Это позволяет совместно используемому модулю, чтобы иметь возможность разделить его различные провайдеры, которые будут использоваться с нетерпеливыми модулями и ленивыми модулями - черезforRoot и forChild .
Конвенция (!!!) позволяет ему быть синглтоном - или, точнее , если вы не будете следовать конвенции-вы не получите синглтона.
Таким образом, если вы загружаете толькоforRootвapp.module, то вы получаете только один экземпляр, потому что вы только должны вызватьforRootэто вapp.module.
Кстати - на этом этапе вы можете забыть оforChild. ленивый загруженный модуль не должен / не будет вызыватьforRoot- так что вы в безопасности в POV синглтона.ForRoot и forChild не являются одним нерушимым пакетом - просто нет смысла вызывать Root , который , очевидно, будет загружен только в
app.module, не давая возможности ленивым модулям иметь свои собственные сервисы, не создавая новых сервисов, которые должны быть синглетными.Настоящая конвенция дать вам хорошую способность под названием
forChild- потреблять "сервисы только для лениво загруженных модулей".Вот демонстрация корневых провайдеров дает положительные числа, ленивые загруженные модули дают отрицательные числа.
Https://www.freelancermap.com/freelancer-tips/12255-forroot-forchild-angular
Это статья об использовании forRoot и forChild в Angular; я не особенно разбираюсь в этой теме, но, возможно, это может быть полезно!

Comments