Render Props最近在React
社區中引發了轟動,可是與之相似的模式在Angular中彷佛並無獲得太多關注。我在以前寫的文章說起過,TemplateRefs
就是Angular
中的Render Props
,同時我會在這篇文章中列舉一個簡單易用的例子。html
Note:TemplateRef
是一個類名而<ng-template>
是一個html
標籤,它們本質上是相同的。不過你可能會在項目中更頻繁地使用<ng-template>
,可是在網上你能夠很容易的搜索到關於TemplateRef
的知識,由於<ng-template>
會給你提供不少html5
中的<template>
標籤的信息。
咱們已有的實現中,使用自定義內容指令(content directives)。當組件做者提早了解使用該toggle
組件的父組件所須要的狀態時,那麼它將會正常的運做。可是若是父組件所須要的狀態並不在咱們的設想以內,咱們該怎麼辦?前端
將toggle
組件的狀態直接提供給父組件,同時容許父組件提供相應的渲染視圖(view
)。html5
<ng-template>
組件能夠完美地解決問題。react
Toggle
組件<toggle>
組件可以經過ContentChild
裝飾器獲得關於<ng-template>
的引用,以後會賦予模板在渲染時所須要的狀態,代碼以下:設計模式
<ng-container *ngTemplateOutlet="layoutTemplate; context: { on: this.on, toggle: this.toggle, fns: { toggle: this.toggle } }"> </ng-container>
這裏<ng-container>
被當作一個佔位符來使用,以後你可使用*ngTemplateOutlet
指令來填充它,layoutTemplate
變量指代的是須要被渲染的模板,context
對象包含的鍵值對會做爲組件狀態注入layoutTemplate
中。性能
從toggle
組件中傳入的狀態是經過let
關鍵字在父組件的<ng-template>
標籤上顯示聲明的。測試
let
關鍵字的使用方式類是這樣的:let-templatevar="inputvar"
,templatevar
指代在<ng-template>
標籤中,關聯組件狀態值的變量名,而inputvar
指代使用<toggle>
組件的模板做用域中的變量名。this
這種語法會有效地避免命名衝突,好比在父組件做用域中已經有一個inputvar
變量了。設計
stackblitz演示地址code
這種組件設計模式按我我的的理解,實際上是依賴倒置原則在視圖渲染層的一種延伸,爲何這麼說呢?是由於一般狀況下子組件視圖的渲染邏輯取決於傳入的props
狀態和自身提供的模板,這在大多數狀況下不會形成任何困擾,可是當咱們沒法在提早得知咱們須要渲染什麼的時候,這個問題就會變得十分棘手。
一種解決方法,咱們可使用條件渲染指令,根據傳入的狀態來斷定組件渲染的狀態,這種解決方法在狀況比較少的狀況下是能夠解決問題的,可是當狀況數量十分龐大的狀況下,增長過多的條件斷定會導致子組件的模板代碼量劇增,同時下降性能,由於每次渲染都會進行若干次條件邏輯判斷。
除了上面的解決方法,就是使用正文中所說起的模式了,這種模式將子組件視圖的渲染邏輯倒置爲子組件僅僅聲明模板中所會使用的狀態變量,對於這些變量和模板的注入工做,全權賦予父組件,所以會使子組件的複用性和可測試性大大提升。
正文中僅列舉了一個簡單的例子中,我這裏在簡單說起一個實際工做可能會用到的例子,就是表單校驗的錯誤提示組件,通常前端組件設計但凡涉及表單,都會是十分複雜的,更不用說校驗這種靈活性很高的功能了。
爲了適應表單校驗的靈活性,咱們使用這種模式會事半功倍,提供校驗信息的組件僅僅聲明渲染表單錯誤提示信息須要設計的狀態變量便可,好比dirty
、touched
等等,對於錯誤信息的文案及樣式,通通交由錯誤提示組件的使用者完成。