We want to hear from you!Take our 2021 Community Survey!

條件 Render

在 React 中,你可以建立不同的 component 來封裝你需要的行為。接著,你可以根據你的應用程式的 state,來 render 其中的一部份。

React 中的條件 rendering 跟 JavaScript 一致。使用 JavaScript 中的運算子如 if 或者 三元運算子 來建立表示目前 state 的 element,然後讓 React 根據它們來更新 UI。

先看以下兩個 component:

function UserGreeting(props) {
  return <h1>Welcome back!</h1>;
}

function GuestGreeting(props) {
  return <h1>Please sign up.</h1>;
}

我們將會建立一個 Greeting component,它會根據使用者是否已登入來顯示其中之一:

function Greeting(props) {
  const isLoggedIn = props.isLoggedIn;
  if (isLoggedIn) {    return <UserGreeting />;  }  return <GuestGreeting />;}
const root = ReactDOM.createRoot(document.getElementById('root'));
// 試改為 isLoggedIn={true}:
root.render(<Greeting isLoggedIn={false} />);

在 CodePen 上試試看吧!

這範例根據 isLoggedIn prop 的值來 render 不同的問候語。

Element 變數

你可以用變數來儲存 element。它可以幫助你有條件地 render 一部份的 component,而保持其他輸出不變。

思考這兩個新的登入和登出按鈕 component:

function LoginButton(props) {
  return (
    <button onClick={props.onClick}>
      Login
    </button>
  );
}

function LogoutButton(props) {
  return (
    <button onClick={props.onClick}>
      Logout
    </button>
  );
}

在下列範例,我們將建立一個名為 LoginControlstateful component

它將根據目前的 state 來 render <LoginButton />< LogoutButton />。而且也會 render 前面範例的 <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;
    if (isLoggedIn) {      button = <LogoutButton onClick={this.handleLogoutClick} />;    } else {      button = <LoginButton onClick={this.handleLoginClick} />;    }
    return (
      <div>
        <Greeting isLoggedIn={isLoggedIn} />        {button}      </div>
    );
  }
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<LoginControl />);

在 CodePen 上試試看吧!

雖然宣告變數並使用 if 語句來有條件 render component 是一個不錯的方式,但有時你也想使用更簡潔的語法。在 JSX 中有以下幾種方法:

Inline If 與 && 邏輯運算子

你可以透過大括號在 JSX 中嵌入表達式,包括 JavaScript 的 && 邏輯運算子,可以方便 render 有條件的 element:

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'];

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Mailbox unreadMessages={messages} />);

在 CodePen 上試試看吧!

能夠這樣做是因為在 JavaScript 中,true && expression 總是回傳 expression ,而 false && expression 總是回傳 false

所以,當條件為 true 時,&& 右側的 element 會出現在輸出中,如果是 false,React 會忽略並跳過它。

請注意,回傳 falsy expression 仍會導致 && 之後的 element 被忽略,但依舊回傳 falsy expression,在下面的範例中,render 將會回傳 <div>0</div>

render() {
  const count = 0;  return (
    <div>
      {count && <h1>Messages: {count}</h1>}    </div>
  );
}

Inline If-Else 與三元運算子

另一個有條件 render element 的方式是透過 JavaScript 的三元運算子 condition ? true : false

在下面的範例,我們會用它來有條件地 render 一小段文字。

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 中一樣,你可以根據團隊習慣來選擇更合適的風格。還要記著如果條件變得過於複雜,也許是個好時機來抽離 component 了。

防止 Component Render

在少數的情況下,你可能希望 component 隱藏自己本身,即便它是由另一個 component 被 render。可以透過回傳 null 而不是它的 render 輸出。

在下面的範例中,<WarningBanner /> 的 render 取決於 warn prop 的值。如果 prop 是 false,它就不會 render。

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(state => ({
      showWarning: !state.showWarning
    }));
  }

  render() {
    return (
      <div>
        <WarningBanner warn={this.state.showWarning} />        <button onClick={this.handleToggleClick}>
          {this.state.showWarning ? 'Hide' : 'Show'}
        </button>
      </div>
    );
  }
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Page />);

在 CodePen 上試試看吧!

在 component 中回傳 null 並不會影響 component 的生命週期方法。例如 componentDidUpdate 依然可以被呼叫。

Is this page useful?Edit this page