# 條件渲染
在 React 中,你可以創建不同的組件封裝你需要的行為。然后,只渲染它們之中的一些,取決于你的應用的狀態。
React 中的條件渲染就和在 JavaScript 中的條件控制一樣。使用 JavaScript 操作符如 [if](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/if...else) 或者[條件操作符](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Conditional_Operator)來創建渲染當前狀態的元素,使 React 更新匹配的 UI 。
思考這兩個組件:
~~~
function UserGreeting(props) {
return <h1>Welcome back!</h1>;
}
function GuestGreeting(props) {
return <h1>Please sign up.</h1>;
}
~~~
我們將創建一個 Greeting 組件來顯示這兩個組件之一,根據用戶是否已經登錄:
~~~
function Greeting(props) {
const isLoggedIn = props.isLoggedIn;
if (isLoggedIn) {
return <UserGreeting />;
}
return <GuestGreeting />;
}
ReactDOM.render(
// 嘗試修改 isLoggedIn={true}:
<Greeting isLoggedIn={false} />,
document.getElementById('root')
);
~~~
在 CodePen 中[打開查看](https://codepen.io/gaearon/pen/ZpVxNq?editors=0011)。
這個例子根據 isLoggedIn prop 渲染了不同的問候語 。
## 元素變量
可以用變量來存儲元素。這可以在其它的輸出沒有改變的時候幫你條件渲染部分組件。
思考這兩個代表 Logout 和 Login 按鈕的兩個新的組件:
~~~
function LoginButton(props) {
return (
<button onClick={props.onClick}>
Login
</button>
);
}
function LogoutButton(props) {
return (
<button onClick={props.onClick}>
Logout
</button>
);
}
~~~
在這個例子中,我們將會創建一個有狀態組件,叫做 LoginControl。
它將渲染 `<LoginButton />` 或者 `<LogoutButton />`,取決于當前狀態。它也會從前面的例子中渲染一個 `<Greeting />`:
~~~
class LoginControl extends React.Component {
constructor(props) {
super(props);
this.handleLoginClick = this.handleLoginClick.bind(this);
this.handleLogoutClick = this.handleLogoutClick.bind(this);
this.state = {isLoggedIn: false};
}
handleLoginClick() {
this.setState({isLoggedIn: true});
}
handleLogoutClick() {
this.setState({isLoggedIn: false});
}
render() {
const isLoggedIn = this.state.isLoggedIn;
let button = null;
if (isLoggedIn) {
button = <LogoutButton onClick={this.handleLogoutClick} />;
} else {
button = <LoginButton onClick={this.handleLoginClick} />;
}
return (
<div>
<Greeting isLoggedIn={isLoggedIn} />
{button}
</div>
);
}
}
ReactDOM.render(
<LoginControl />,
document.getElementById('root')
);
~~~
在 CodePen 中[打開查看](https://codepen.io/gaearon/pen/QKzAgB?editors=0010)。
雖然聲明一個變量并使用一個 if 語句是對組件進行條件渲染的好方法,但有時你可能希望使用一個更短的語法。在 JSX 中還有一些內聯的條件用法,下面進行解釋。
## 使用邏輯 && 操作符的內聯 if 用法
在[ JSX 中你可以嵌入任何表達式到花括號](https://facebook.github.io/react/docs/introducing-jsx.html#embedding-expressions-in-jsx)中。也包括 JavaScript 的邏輯 && 操作符。這在一個元素中進行條件編寫是非常方便的:
~~~
function Mailbox(props) {
const unreadMessages = props.unreadMessages;
return (
<div>
<h1>Hello!</h1>
{unreadMessages.length > 0 &&
<h2>
You have {unreadMessages.length} unread messages.
</h2>
}
</div>
);
}
const messages = ['React', 'Re: React', 'Re:Re: React'];
ReactDOM.render(
<Mailbox unreadMessages={messages} />,
document.getElementById('root')
);
~~~
在 CodePen 中[打開查看](https://codepen.io/gaearon/pen/ozJddz?editors=0010)。
它可以正常運行,因為在 JavaScript 中, true && 表達式總是會執行為 expression,而 false && expression 總是執行為 false 。
因此,如果條件為 true ,&& 之后的元素會在輸出中顯示。如果為 false,React 將會忽略并跳過它。
## 使用條件操作符的內聯 if...else
另一個用于條件渲染元素的內聯方法是使用 JavaScript 的條件操作符 [condition ? true : false](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Conditional_Operator) 。
在這個例子中,我們使用它來進行條件渲染一個小的文本塊:
~~~
render() {
const isLoggedIn = this.state.isLoggedIn;
return (
<div>
The user is <b>{isLoggedIn ? 'currently' : 'not'}</b> logged in.
</div>
);
}
~~~
還可以用于較大的表達式,即使它不太明顯接下來的行為:
~~~
render() {
const isLoggedIn = this.state.isLoggedIn;
return (
<div>
{isLoggedIn ? (
<LogoutButton onClick={this.handleLogoutClick} />
) : (
<LoginButton onClick={this.handleLoginClick} />
)}
</div>
);
}
~~~
就像在 JavaScript 中,這取決于你選擇一個認為適合你和你的團隊認為更加好用的方式。另外要記得,無論何時條件變得復雜時,是時候來提取一個組件了。
## 在組件中防止渲染
在某些少用的場景,你可能需要一個組件隱藏自己,即使它是被另一個組件渲染的。可以通過 return null 而不是返回它的渲染輸出來實現。
在下面的例子中, `<WarningBanner />` 是否渲染,取決于一個叫做 warn 的prop 的值。如果值是 false,那么組件不會被渲染:
~~~
function WarningBanner(props) {
if (!props.warn) {
return null;
}
return (
<div className="warning">
Warning!
</div>
);
}
class Page extends React.Component {
constructor(props) {
super(props);
this.state = {showWarning: true}
this.handleToggleClick = this.handleToggleClick.bind(this);
}
handleToggleClick() {
this.setState(prevState => ({
showWarning: !prevState.showWarning
}));
}
render() {
return (
<div>
<WarningBanner warn={this.state.showWarning} />
<button onClick={this.handleToggleClick}>
{this.state.showWarning ? 'Hide' : 'Show'}
</button>
</div>
);
}
}
ReactDOM.render(
<Page />,
document.getElementById('root')
);
~~~
在 CodePen 中[打開查看](https://codepen.io/gaearon/pen/Xjoqwm?editors=0010)。