本期精讀的文章是:8 React conditional rendering methodshtml
介紹了八種 React 條件渲染方式。react
模版條件渲染很是常見,遇到的時候每每會隨機選擇一種方式使用,那麼怎麼寫會有較好的維護性呢?先一塊兒瞭解下有哪八種條件渲染方式吧!git
既然 JSX 支持 js 與 html 混寫,那麼交替使用就能解決條件渲染的問題:程序員
function render() { if (renderComponent1) { return <Component1 />; } else { return <div />; } }
null
若是不想渲染空元素,最好使用 null
代替空的 div
:github
function render() { if (renderComponent1) { return <Component1 />; } else { return null; } }
這樣對 React 渲染效率有提高。typescript
將組件賦值到變量,就能夠在 return 前任意修改它了。編程
function render() { let component = null; if (renderComponent1) { component = <Component1 />; } return component; }
三元運算符的語法以下:函數
condition ? expr_if_true : expr_if_false
用在 JSX 上也很方便:spa
function render() { return renderComponent1 ? <Component1 /> : null; }
但三元運算符產生嵌套時,理解成本會變得很高。code
這個是最經常使用了,由於代碼量最少。
function render() { return renderComponent1 && <Component1 />; }
IIFE 含義是當即執行函數,也就是以下代碼:
(function myFunction(/* arguments */) { // ... })(/* arguments */);
當深陷 JSX 代碼中,又想寫一大塊邏輯時,除了回到上方,還可使用 IIFE:
function render() { return ( <div> {(() => { if (renderComponent1) { return <Component1 />; } else { return <div />; } })()} </div> ); }
這是 IIFE 的變種,也就是把這段當即執行函數替換成一個普通函數:
function render() { return ( <div> <SubRender /> </div> ); } function SubRender() { if (renderComponent1) { return <Component1 />; } else { return <div />; } }
作一個條件渲染組件 IF
代替 js 函數的 if
:
<If condition={true}> <span>Hi!</span> </If>
這個組件實現也很簡單
const If = props => { const condition = props.condition || false; const positive = props.then || null; const negative = props.else || null; return condition ? positive : negative; };
高階組件,就是返回一個新組件的函數,而且接收一個組件做爲參數。
那麼咱們就能在高階組件裏寫條件語句,返回不一樣的組件便可:
function higherOrderComponent(Component) { return function EnhancedComponent(props) { if (condition) { return <AnotherComponent {...props} />; } return <Component {...props} />; }; }
這麼多方法都能實現條件渲染,那麼重點在於可讀性與可維護性。
好比經過調用函數實現組件渲染:
<div>{renderButton()}</div>
看上去仍是比較冗餘,若是使用 renderButton
getter 定義,咱們就能夠這麼寫它:
<div>{button}</div>
其實咱們想要的就是 button,而不是 renderButton
。那麼還能夠進一步,乾脆封裝成 JSX 組件:
<div> <Button /> </div>
是否要付出這些努力,取決於應用的複雜度。若是應用複雜度很是高,那你應當儘可能使用最後一種封裝,讓每一個文件的邏輯儘可能獨立、簡單。
若是應用複雜度比較低,那麼注意不要過分封裝,以避免把本身繞進去。
因此看來這又是一個沒有固定答案的問題,選擇何種方式封裝,取決於應用複雜度。
對任何代碼封裝,都會增長這段 鏈接邏輯 的複雜度。
假定不管如何代碼的複雜度都是恆定不變的,下面這段代碼,鏈接複雜度爲 0,而對於 render
函數而言,邏輯複雜度是 100:
function render() { if (renderComponent) { return isOk ? <Component1 /> : <Component2 />; } else { return <div />; } }
下面這段代碼拆成了兩個函數,邏輯複雜度對 render
SubComponent
來講都是 50,但鏈接複雜度是 50:
function render() { if (renderComponent) { return <SubComponent>; } else { return <div />; } } function SubComponent() { return isOk ? <Component1 /> : <Component2 /> }
能夠看到,咱們經過函數拆分,下降了每一個函數的邏輯複雜度,但卻提升了鏈接複雜度。
下面來作一個比較,咱們假設一個正常的程序員,能夠一次性輕鬆記憶 10 個函數。若是再多,函數之間的調用關係就會讓人摸不着頭腦。
在應用代碼量比較小時,假設一共有 10 個函數,若是作了邏輯抽象,拆分出了 10 個子函數,那麼總邏輯複雜度不變,函數變成了 20 個。
此時小王要修改此項目,他須要找到關鍵代碼的位置。
若是沒有作邏輯抽象,小王一會兒就記住了 10 個函數,而且很快完成了需求。
若是應用作了邏輯抽象,他須要理解的邏輯複雜度是不變的,可是要讀的函數變成了 20 個。小王須要像偵探同樣在線索中不斷跳轉,他仍是隻找了 10 個關鍵函數,但一共也就 20 個函數,邏輯並不複雜,這值得嗎?
小王內心可能會嘀咕:簡單的邏輯瞎抽象,害我文件找了半天!
此時應用代碼量比較大,假設一共有 500 個函數,咱們不考慮抽象後帶來的複用好處,假設都沒法複用,那麼作了邏輯抽象後,那麼總邏輯複雜度不變,函數變成了 1000 個。
此時小王接到了需求,終於維護了一個大項目。
小王知道這個項目很複雜,從一開始就沒以爲能理解項目全貌,因此把本身看成一名偵探,準備一步步探索。
如今有兩種選擇,一種是在未作邏輯抽象時探索,一種是在作過邏輯抽象後探索。
若是沒作邏輯抽象,小王須要面對 500
個這種函數:
function render() { if (renderComponent) { return isOk ? <Component1 /> : <Component2 />; } else { return isReady ? <Component3 /> : <Component4 />; } }
若是作了邏輯抽象,小王須要面對 1000
個這種函數:
function render() { if (renderComponent) { return <Component1And2 />; } else { return <Component3And4 />; } }
在項目龐大後,總函數數量並不會影響對線索的查找,而總線索深度也幾乎老是固定的,通常在 5 層左右。
小王理解 5 個或 10 個函數成本都差很少,但沒有作邏輯抽象時,這 5 個函數各自參雜了其餘邏輯,反而影響對函數的理解。
這時作邏輯抽象是合適的。
因此總的來講,筆者更傾向使用子函數、子組件、IF 組件、高階組件作條件渲染,由於這四種方式都能提升程序的抽象能力。
每每抽象後的代碼會更具備複用性,單個函數邏輯更清晰,在切面編程時更利於理解。
當項目很簡單時,整個項目的理解成本都很低,抽象帶來的複雜度反而讓項目變成了須要切面編程的時候,就得不償失了。
總結一下:
&&
或者三元運算符、IIFE 等直接實現條件渲染。討論地址是: 精讀《React 八種條件渲染》 · Issue #90 · dt-fe/weekly
若是你想參與討論,請點擊這裏,每週都有新的主題,週末或週一發佈。