本期精讀的文章是: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 等直接實現條件渲染。若是你想參與討論,請點擊這裏,每週都有新的主題,週末或週一發佈。