條件 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} />);
這範例根據 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>
);
}
在下列範例,我們將建立一個名為 LoginControl
的 stateful 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 />);
雖然宣告變數並使用 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} />);
能夠這樣做是因為在 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 />);
在 component 中回傳 null
並不會影響 component 的生命週期方法。例如 componentDidUpdate
依然可以被呼叫。