此文章是翻译conditional rendering这篇React(版本v16.2.0)官方文档。

Conditional Rendering

在React 中,你可以创建不同的组件,去封装你需要的行为。话说回来,你可以根据你的应用状态,只渲染其中部分组件。

在React 中条件渲染的工作流程同JavaScript 中的条件工作流程一样。利用JavaScript 操作符例如if 或者是条件操作符(conditional operator)去新建元素代表当前状态,然后让React 更新UI 去匹配它们。

考虑一下两个组件:

  1. function UserGreeting(props) {
  2. return <h1>Welcome back!</h1>;
  3. }
  4. function GuestGreeting(props) {
  5. return <h1>Please sign up.</h1>;
  6. }

我们新建一个Greeting 组件来基于一个用户是否已经登录这个两个状态来展示:

  1. function Greating(props) {
  2. const isLoggedIn = props.isLoggedIn
  3. if(isLoggedIn){
  4. return <UserGreeting />;
  5. }
  6. return <GuestGreeting />;
  7. }
  8. ReactDOM.render(
  9. // Try changeing to isLoggedIn={true}
  10. <Greeting isLoggedIn={false} />,
  11. document.getElementById('root')
  12. );

在CodePen 上尝试

上面这个例子展示了根据isLoggedIn props 的值来渲染不同的greeting。

Element Variables

你可以使用变量来存储元素。这样可以帮助你条件渲染一部分组件,同时其他剩余组件不改变。

考虑到下面两个新组件来代表Logout 和Login 按钮:

  1. function LoginButton(props) {
  2. return (
  3. <button onClick={props.onClick}>
  4. Login
  5. </button>
  6. )
  7. }
  8. function LogoutButton(props) {
  9. return (
  10. <button onClick={props.onClick}>
  11. Logout
  12. </button>
  13. )
  14. }

在下面这个例子中,我们将会创建一个叫LoginControl 有状态组件)。

它将根据当前状态要么渲染<LoginButton />要么渲染<LogoutButton />。它也会渲染之前例子中的<Greeting /> 这个组件:

  1. class LoginControl extends React.Component {
  2. constructor(props) {
  3. super(props);
  4. this.handleLoginClick = this.handleLoginClick.bind(this);
  5. this.handleLogoutClick = this.handleLogoutClick.bind(this);
  6. this.state = {isLoggedIn: false};
  7. }
  8. handleLoginClick() {
  9. this.setState({isLoggedIn: true});
  10. }
  11. handleLogoutClick() {
  12. this.setState({isLoggedIn: false});
  13. }
  14. render() {
  15. const isLoggedIn = this.state.isLoggedIn;
  16. let button = null
  17. if (isLoggedIn) {
  18. button = <LogoutButton onClick={this.handleLogoutClick}/>;
  19. } else {
  20. button = <LoginButton onClick={this.handleLoginClick} />;
  21. }
  22. return (
  23. <div>
  24. <Greating isLoggedIn={isLoggedIn}/>
  25. {button}
  26. </div>
  27. );
  28. }
  29. }
  30. ReactDOM.render(
  31. <LoginControl />,
  32. document.getElementById('root')
  33. );

在CodePen 上尝试

当声明了一个变量并且使用if 语句是一个好方式去条件渲染一个组件,有时你可能想要使用更短的语法(a shorter syntax)。下面来介绍几种在JSX 中使用行内条件(inline conditions)

Inline if with Logical && Operator

你可以在JSX 中嵌入任何表达式)通过使用大括号包裹它们。这里包括JavaScript &&(逻辑与 ) 操作符。它可以很方便作为条件在一个元素中:

  1. function Mailbox(props) {
  2. const unreadMessages = props.unreadMessages;
  3. return (
  4. <div>
  5. <h1>Hello!</h1>
  6. {unreadMessages.length > 0 &&
  7. <h2>
  8. You have {unreadMessages.length} unreadMessages.
  9. </h2>
  10. }
  11. </div>
  12. );
  13. }
  14. const messages = ['React', 'Re: React', 'Re:Re: React'];
  15. ReactDOM.render(
  16. <Mailbox unreadMessages={messages} />,
  17. document.getElementById('root')
  18. );

在CodePen 上尝试

在JavaScript 中它是工作的,true&&expression 总是计算成expression,而false&&expression 总是计算成false

因此,如果条件是true,位于&& 右侧的元素会在输出中显示,如果是false,React 会忽略并且跳过它。

Inline If-Else with Condtional Operator

另一个行内条件渲染元素的方式是使用条件操作符condition ? true : false

在下面这个例子中,我们使用它来条件渲染一小块文字。

  1. render() {
  2. const isLoggedIn = this.state.isLoggedIn;
  3. return (
  4. <div>
  5. The user is <b>{isLoggedIn ? 'currently' : 'not'}</b> logged in.
  6. </div>
  7. );
  8. }

它可以被用作大的表达式,虽然对将要发生什么并不明显:

  1. render() {
  2. const isLoggedIn = this.state.isLoggedIn;
  3. return (
  4. <div>
  5. {isLoggedIn ? (
  6. <LogoutButton onClick={this.handleLogoutClick} />
  7. ) : (
  8. <LoginButton onClick={this.handleLoginClick} />
  9. )}
  10. </div>
  11. );
  12. }

就像在JavaScript,它只依赖你和你的团队对考虑可读性来选择一个合适的方式。同时记住无论什么时候只要条件变得太复杂,去(提取出一个组件](https://reactjs.org/docs/components-and-props.html#extracting-components))是更好的方式。

Preventing Component from Rendering

在少数情况下,你可能要想隐藏一个组件,即使这个组件已经被另一个组件渲染了。通过返回null 来代替输出。

在下面这个例子中,这个<WarningBanner /> 被渲染依赖warn prop 值。如果这个prop 的值是false,那么这个组件不被渲染:

  1. function WarningBanner(props) {
  2. if(!props.warn){
  3. return null;
  4. }
  5. return (
  6. <div className="warning">
  7. Warninig!
  8. </div>
  9. );
  10. }
  11. class Page extends React.Component {
  12. constructor(props) {
  13. super(props);
  14. this.state = {showWarning: true};
  15. this.handleToggleClick = this.handleToggleClick.bind(this);
  16. }
  17. handleToggleClick() {
  18. this.setState((prevState) => ({
  19. showWarning: !prevState.showWarning
  20. }));
  21. }
  22. render() {
  23. return(
  24. <div>
  25. <WarningBanner warn={this.state.showWarning} />
  26. <button onClick={this.handleToggleClick}>
  27. {this.state.showWarning ? 'Hide': 'Show'}
  28. </button>
  29. </div>
  30. );
  31. }
  32. }
  33. ReactDOM.render(
  34. <Page />,
  35. document.getElementById('root')
  36. );

在CodePen 上尝试

从组件的render方法返回null不会影响组件生命周期方法的触发。 例如,componentWillUpdatecomponentDidUpdate 仍将被调用。