翻譯:瘋狂的技術宅
原文:blog.logrocket.com/returning-n…
未經允許嚴禁轉載
概述
在 React 16 中為了防止不必要的 DOM 更新,允許你決定是否讓 .setState
更來新狀態。在呼叫 .setState
時返回 null
將不再觸發更新。
我們將通過重構一個 mocktail (一種不含酒精的雞尾酒)選擇程式來探索它是如何工作的,即使我們選擇相同的 mocktail 兩次也會更新。
目錄結構如下所示:
src
|-> App.js
|-> Mocktail.js
|-> index.js
|-> index.css
|-> Spinner.js
複製程式碼
我們的程式如何工作
我們的程式將顯示一個被選中的 mocktail。可以通過單擊按鈕來選擇或切換 mocktail。這時會載入一個新的 mocktail,並在載入完成後渲染出這個 mocktail 的影象。
App
元件的父元件有 mocktail
狀態和 updateMocktail
方法,用於處理更新 mocktail。
import React, { Component } from 'react';
import Mocktail from './Mocktail';
class App extends Component {
state = {
mocktail: ''
}
updateMocktail = mocktail => this.setState({ mocktail })
render() {
const mocktails = ['Cosmopolitan', 'Mojito', 'Blue Lagoon'];
return (
<React.Fragment>
<header>
<h1>Select Your Mocktail</h1>
<nav>
{
mocktails.map((mocktail) => {
return <button
key={mocktail}
value={mocktail}
type="button"
onClick={e => this.updateMocktail(e.target.value)}>{mocktail}</button>
})
}
</nav>
</header>
<main>
<Mocktail mocktail={this.state.mocktail} />
</main>
</React.Fragment>
);
}
}
export default App;
複製程式碼
在 button
元素的 onClick
事件上呼叫 updateMocktail
方法,mocktail
狀態被傳遞給子元件 Mocktail
。
Mocktail
元件有一個名為 isLoading
的載入狀態,當其為 true
時會渲染 Spinner
元件。
import React, { Component } from 'react';
import Spinner from './Spinner';
class Mocktail extends Component {
state = {
isLoading: false
}
componentWillReceiveProps() {
this.setState({ isLoading: true });
setTimeout(() =>
this.setState({
isLoading: false
}), 500);
}
render() {
if (this.state.isLoading) {
return <Spinner/>
}
return (
<React.Fragment>
<div className="mocktail-image">
<img src={`img/${this.props.mocktail.replace(/ +/g, "").toLowerCase()}.png`} alt={this.props.mocktail} />
</div>
</React.Fragment>
);
}
}
export default Mocktail;
複製程式碼
在 Mocktail
元件的 componentWillReceiveProps
生命週期方法中呼叫 setTimeout
,將載入狀態設定為 true
達 500 毫秒。
每次使用新的 mocktail
狀態更新 Mocktail
元件的 props 時,它會用半秒鐘顯示載入動畫,然後渲染 mocktail 影象。
問題
現在的問題是,即使狀態沒有改變,mocktail
狀態也會被更新,同時觸發重新渲染 Mocktail
元件。
例如每當單擊 Mojito 按鈕時,我們都會看到程式對 Mojito 影象進行了不必要地重新渲染。 React 16 對狀態效能進行了改進,如果新的狀態值與其現有值相同的話,通過在 setState
中返回 null
來防止來觸發更新。
解決方案
以下是我們將要遵循的步驟,來防止不必要的重新渲染:
- 檢查新的狀態值是否與現有值相同
- 如果值相同,我們將返回
null
- 返回
null
將不會更新狀態和觸發元件重新渲染
首先,在 app
元件的 updateMocktail
方法中,建立一個名為 newMocktail
的常量,並用傳入的 mocktail
值為其賦值。
updateMocktail = mocktail => {
const newMocktail = mocktail;
this.setState({
mocktail
})
}
複製程式碼
因為我們需要基於之前的狀態檢查和設定狀態,而不是傳遞 setState
和 object
,所以我們需要傳遞一個以前的狀態作為引數的函式。然後檢查 mocktail
狀態的新值是否與現有值相同。
如果值相同,setState
將返回 null
。否則 setState
返回更新的 mocktail
狀態,這將觸發使用新狀態重新渲染 Mocktail
元件。
updateMocktail = mocktail => {
const newMocktail = mocktail;
this.setState(state => {
if (state.mocktail === newMocktail) {
return null;
} else {
return { mocktail };
}
})
}
複製程式碼
現在單擊按鈕仍會載入其各自的 mocktail 影象。但是,如果我們再次單擊同一個mocktail按鈕,React 不會重新渲染 Mocktail
元件,因為 setState
返回 null
,所以狀態沒有改變,也就不會觸發更新。
我在下面的兩個 GIF 中突出顯示了 React DevTools 中的更新:
**注意:**我在這裡換了一個深色主題,以便更容易觀察到 React DOM 中的更新。
總結
本文介紹了在 React 16 中怎樣從 setState
返回 null
。我在下面的 CodeSandbox
中新增了 mocktail
選擇程式的完整程式碼,供你使用和 fork。
CodeSandbox:codesandbox.io/embed/vj8wk…
通過使用 null
可以防止不必要的狀態更新和重新渲染,這樣使我們的程式執行得更快,從而改善程式的使用者體驗。
使用者偶然發現我們的產品,他們對產品的看法直接反映了對公司及其產品的看法,因此我們需要以自然和直觀的方式圍繞使用者的期望去構建體驗。
希望本文能夠對你有所幫助。感謝閱讀!