# 条件渲染
在 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)。