React中的條件渲染
React 中的條件渲染有以下幾種方式:
- if 語句
- 三元操作符(ternary operator)
- 邏輯 && 操作符
- switch.. case.. 語句
- 列舉(enums)
- 多層條件渲染(multi-level conditional reandering)
- 使用高階元件
1.if 語句
在React中使用if語句條件渲染是最簡單的。比如List元件如果沒有任何items,可以提前return
function List({ list }) { if (!list) { return null; } return ( <div> {list.map(item => <ListItem item={item} />)} </div> ); }
一個元件如果return null
,將不會被渲染出來。如果你想給使用者一些反饋,當list為空時,可以採用下面方式:
function List({ list }) { // list 為null的情況 if (!list) { return null; } // list 為空的情況 if (!list.length) { return <p>sorry, the list is empty</p> } else { return ( <div> {list.map(item => <ListItem item={item} />)} </div> ); } }
if...else 是最基本的條件渲染方式。
2.三元操作符
可以使用三元運算子來代替上面的if...else...
條件渲染。
例如,你想從2種模式(edit, view)中切換,可以使用布林值來決定那個元件被渲染:
function Item({ item, mode }) { const isEditMode = mode === 'EDIT'; return ( <div> { isEditMode ? <ItemEdit item={item} /> : <ItemView item={item}> } </div> ); }
三元運算子使條件渲染更加的簡潔,使得程式碼可以採用內聯(inline)的方式表達出來
3.邏輯 '&&' 操作符
這個是當你想渲染一個元件或者什麼也不渲染的情況。
例如,有一個 LoadingIndicator
元件,返回載入文字或者什麼也沒有。當然可以使用if...else或者三元運算子,如下:
function LoadingIndicator({ isLoading }) {
if (isLoading) {
return (
<div>
<p>Loading...</p>
</div>
);
} else {
return null;
}
}
function LoadingIndicator({ isLoading }) {
return (
<div>
{ isLoading
? <p>Loading...</p>
: null
}
</div>
);
}
使用 &&
可以使返回 null 的情況的條件渲染更加的簡潔:
function LoadingIndicator({ isLoading }) {
return (
<div>
{ isLoading && <p>Loading...</p> }
</div>
);
}
4.switch...case語句
我們有可能遇到多種條件渲染的情況,例如依據不同的state渲染不同的Component.
例如,Notification 元件根據輸入狀態可能渲染Error,Warning,Info三種不同的元件。這個時候可以使用switch...case來進行多種條件渲染:
function Notification({ text, state }) {
switch (state) {
case 'info':
return <Info text={text} />;
case 'warning':
return <Warning text={text} />;
case 'info':
return <Info text={text} />;
default:
return null;
}
}
注意switch...case語句永遠要加上default情況,因為React元件要麼返回元素,要麼返回null
另外值得注意的是,如果元件依據 state 屬性 渲染時,最後新增上 React.PropTypes,即上面的元件後面新增:
Notification.propTypes = {
text: React.PropTypes.string,
state: React.PropTypes.oneOf(['info', 'warning', 'error'])
}
另一種將條件渲染結果內聯在switch...case中的方法是,使用立即呼叫函式
function Notification({ text, state }) {
return (
<div>
{(() => {
switch (state) {
case 'info':
return <Info text={text} />;
case 'warning':
return <Warning text={text} />;
case 'info':
return <Info text={text} />;
default:
return null;
}
})()}
</div>
);
}
switch...case
幫助我們在多種條件中渲染中使用,但是多種條件渲染最好的方式是列舉
5.列舉(Enums)
在javascript中,物件的鍵值對可以用作列舉:
const ENUM = {
a: '1',
b: '2',
c: '3'
};
列舉是多種條件渲染中很好的一種方式,上面的 Notification 元件可以寫為:
function Notification({ text, state }) {
return (
<div>
{{
info: <Info text={text} />,
warning: <Warning text={text} />,
error: <Error text={text} />
}[state]}
</div>
)
}
上面的 state 屬性用於取回物件中的值,這比switch...case可讀性更強。
因為物件的值依賴 text
屬性,所以我們必須使用內聯物件。如果我們不需要text屬性,我們可以使用外部靜態列舉:
const NOTIFICATION_STATES = {
info: <Infor />,
warning: <Warning />,
error: <Error />,
};
function Notification({ state }) {
return (
<div>
{NOTIFICATION_STATES[state]}
</div>
)
}
如果我們需要text屬性,我們可以使用函式取回物件的值
const getSpecificNotification = (text) => ({
info: <Info text={text} />,
warning: <Warning text={text} />,
error: <Error text={text} />,
});
function Notification({ state, text }) {
return (
<div>
{getSpecificNotification(text)[state]}
</div>
)
}
物件用作列舉,使用場景很靈活,下面例子:
function FooBarOrFooOrBar({ isFoo, isBar }) {
const key = `${isFoo}-${isBar}`;
return (
<div>
{{
['true-true']: <FooBar />,
['true-false']: <Foo />,
['false-true']: <Bar />,
['false-false']: null,
}[key]}
</div>
);
}
FooBarOrFooOrBar.propTypes = {
isFoo: React.PropTypes.boolean.isRequired,
isBar: React.PropTypes.boolean.isRequired
}
6.多層條件渲染
我們有時候可能碰到巢狀條件選擇渲染的情況。
例如,List元件可能顯示一個list,或者一個empty text提示,或者什麼多沒有:
function List({ list }) {
const isNull = !list;
const isEmpty = !isNull && !list.length;
return (
<div>
{ isNull
? null
: ( isEmpty
? <p>Sorry, the list is empty</p>
: <div>{list.map(item => <ListItem item={item} />)}</div>
)
}
</div>
);
}
// 例項
<List list={null} /> // <div></div>
<List list={[]} /> // <div><p>Sorry, the list is empty</p></div>
<List list={['a', 'b', 'c']} /> // <div><div>a</div><div>b</div><div>c</div></div>
但是最好保持巢狀的層數最小化,這樣程式碼可讀性更強。可以將元件劃分成更小的元件的方式
function List({ list }) {
const isList = list && list.length;
return (
<div>
{ isList
? <div>{list.map(item => <ListItem item={item} />)}</div>
: <NoList isNull={!list} isEmpty={list && !list.empty} />
}
</div>
);
}
function NoList({ isNull, isEmpty }) {
return (!isNull && isEmpty) && <p>Sorry, the list is empty</p>
}
7.高階元件用作條件渲染
HOCs 在React中很適合條件渲染。HOCs的一種使用方式就是改變元件的外觀。
例如使用高階元件來展示一個載入顯示器或者一個想要的元件:
function withLoadingIndicator(Component) {
return function EnhancedComponent({ isLoading, ...props }) {
if (!isLoading) {
return <Component { ...props } />;
}
return <div><p>Loading...</p></div>;
}
}
// 使用
const ListWithLoadingIndicator = withLoadingIndicator(List);
<ListWithLoadingIndicator
isLoading={props.isLoading}
list={props.list}
/>
這個示例中,List元件能關注渲染list上,而不必擔心loading狀態,另外,HOCs可以遮蔽list為null或empty的情況。
總結
使用上面的哪一種條件渲染可以根據下面的一些情況而定:
-
if-else
- 最簡單的條件渲染
- 適用於新手
- 使用if,從渲染方法中返回null提前退出函式
-
三元操作符
- 比if-else更好,優先使用
- 比if-else更加簡潔
-
邏輯 '&&' 操作符
- 不返回元素就返回null時使用
-
switch...case
- 比較冗長
- 可以通過立即呼叫函式內聯使用
- 使用列舉的方式代替這種方式更好
-
列舉(enums)
- 使用於不同的狀態使用
- 超過一種條件選擇時使用
-
多層次條件選擇渲染
- 避免使用這種方式對可讀性的影響
- 將元件劃分為更小的元件,小元件自身帶有條件選擇
- 偏向於使用高階元件(HOCs)
-
HOCs
- 使用高階元件而遮蔽條件渲染
- 元件能關注主要的邏輯目的