【转】React 16 中从 setState 返回 null 的妙用
概述
在 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() {
<span class="hljs-keyword">const</span> mocktails = [<span class="hljs-string">'Cosmopolitan'</span>, <span class="hljs-string">'Mojito'</span>, <span class="hljs-string">'Blue Lagoon'</span>];<span class="hljs-keyword">return</span> (<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 = {<span class="hljs-attr">isLoading</span>: <span class="hljs-literal">false</span> }componentWillReceiveProps() {<span class="hljs-keyword">this</span>.setState({ <span class="hljs-attr">isLoading</span>: <span class="hljs-literal">true</span> });setTimeout(<span class="hljs-function"><span class="hljs-params">()</span> =></span> <span class="hljs-keyword">this</span>.setState({<span class="hljs-attr">isLoading</span>: <span class="hljs-literal">false</span>}), <span class="hljs-number">500</span>); }render() {<span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.state.isLoading) {<span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag"><<span class="hljs-name">Spinner</span>/></span></span>}<span class="hljs-keyword">return</span> (<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 來防止來觸發更新。
解決方案
以下是我們將要遵循的步驟,來防止不必要的重新渲染:
首先,在 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 中的更新:
沒有從 setState 返回 null 從 setState 返回 null 之后**注意:**我在這里換了一個深色主題,以便更容易觀察到 React DOM 中的更新。
總結
本文介紹了在 React 16 中怎樣從 setState 返回 null。我在下面的 CodeSandbox 中添加了 mocktail 選擇程序的完整代碼,供你使用和 fork。
CodeSandbox:codesandbox.io/embed/vj8wk…
通過使用 null 可以防止不必要的狀態更新和重新渲染,這樣使我們的程序執行得更快,從而改善程序的用戶體驗。
轉自在 React 16 中從 setState 返回 null 的妙用
總結
以上是生活随笔為你收集整理的【转】React 16 中从 setState 返回 null 的妙用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Mysql主从复制详解和实战
- 下一篇: 记一次中台数据传输同步Elasticse