ItIron2023
react
昨天我們談到了多個類似的state在同一組件的管理問題,以及你可以如何利用一個共用的hanlder去優化,今天我們換個主題,把重點先從useState抽開換換口味。
條件渲染是一個你幾乎在實務中無法避免的東西,由於條件渲染搞出的狀態自然也是層出不窮,今天要看的同樣是一個不算罕見的情況,我自己在第一份工作時就有不小心犯過這個錯誤,馬上來看一下吧!
請一樣先看一下這個codesandbox,題目是個很單純的條件渲染,我們有個friends陣列用來展示該使用者的所有朋友,並想在陣列長度為0的情況下渲染出其他的訊息,同時我們有個setTimeout去模擬請求資料的行為,在收到資料前陣列為空。
最終畫面雖然如我們預期的變動成展示完整的朋友名單,但在取得資料前卻有個奇怪的0出現在頁面上,請試著修復這個問題。
export default function App() {
const [friends, setFriends] = useState([]);
useEffect(() => {
// use a timeout to simulate fetch request
setTimeout(() => {
setFriends(DEFAULT_LIST_FOR_DEMO);
}, 1500);
}, []);
return (
<div className="App">
<h1>An unexpected "0" in the page while doing conditional rendering</h1>
{friends.length && (
<div>
{friends.map((friend) => (
<div key={friend.id}>This is your friend, {friend.name}</div>
))}
</div>
)}
{!friends.length && <p>I am sorry, you have no friends</p>}
</div>
);
}
這類的情況往往出現在條件渲染時,尤其是陣列的情況為多,原因在於許多人會利用像是array.length這樣的條件判斷是否該渲染某些元素,畢竟我們在寫js條件式的時候就很喜歡善用(濫用)js的自動轉型機制,很多時候我們會寫出類似這樣的條件
if (arr.length) {
// do something
}
接著就不小心把這樣的思維帶到react中了,雖然0、null、undefined之類的falsy value會因為自動轉型的關係讓你條件式如你所想運作,但在渲染時就不完全是這麼一回事了。
舉個例子來說,你在傳統的html寫了類似這樣的東西,你也不會期待0就這樣消失,他還是一個很單純的元素,並不是因為falsy value它就不渲染。
<h1>0</h1>
至於為什麼null & false這樣的值也不會被渲染,那就跟react的機制有關係了,react將null
& false
視為 no-rendering,因此這類的值並不會在畫面上出現,這個小巧思也給了我們彈性讓我們可以有效率的撰寫條件渲染。 理解這一點後我們來看一下程式碼,我想你就會瞭解了
{friends.length && (
// some code here
)}
當左邊為0時,此時程式碼等價於
{0 && (
// some code here
)}
而&&運算子的規則很簡單,若運算子左邊的值可以轉為true,此時回傳右手邊的值,反之回傳左手邊的值,舉幾個簡單的例子
1 && 2 => 2
1 && 0 => 0
0 && 1 => 0
因此在資料回傳前,長度為0的陣列經過上方的運算自然會回傳0,最終渲染在畫面上,理解這點後解決方法就很簡單了,有數種不同的方式你可以使用,但原則都是一樣的,不要用數字當條件渲染的值,比方說你可以用以下兩種寫法,都能解決你的問題!
{friends.length > 0 && (
// some code here
)}
// or
{!!friends.length && (
// some code here
)}
藉由讓運算子左邊變為布林值會是最好的做法,也可以避免更多類似的情況!
我們今天快速看了一個新手常見的條件渲染錯誤,同時幫讀者複習了一下關於js運算子的一些小常識,相信理解原因後一切都沒有這麼莫名其妙了對吧? 條件渲染還會在陪我們一陣子,我們明天見囉!
本文章同步發布於個人部落格,有興趣的朋友也可以來逛逛~!
作者您好
因為使用了setTimeout 所以畫面會在1.5s後才會setFriends
所以在這時候friends陣列裡並沒有值,所以當下方 &&運算子判斷的時候會回傳0在畫面上.
1.5s重新渲染後才會顯示值出來.
好像也能使用三元運算子:?的方式
一開始的時候friends陣列為0
0 在條件判斷時是false
{friends.length ? (
<div>
{friends.map((friend) => (
<div key={friend.id}>This is your friend, {friend.name}</div>
))}
</div>
) : (
<p>I am sorry, you have no friends</p>
)}
理解錯了話請糾正我 感謝作者的好文
lijun 理解正確,三元運算也是在寫jsx經常運用到的技巧,以這個範例來說確實也是解決問題的方法之一!Good job! 唯一你需要注意的是每個團隊對於在jsx中用三元運算的規範,曾經有聽過有些團隊會為了可讀性而盡量避免這樣的寫法,但邏輯上是完全沒有問題的!