翻譯:瘋狂的技術宅原文:https://blog.logrocket.com/re...css
未經容許嚴禁轉載前端
在 React 16 中爲了防止沒必要要的 DOM 更新,容許你決定是否讓 .setState
更來新狀態。在調用 .setState
時返回 null
將再也不觸發更新。react
咱們將經過重構一個 mocktail (一種不含酒精的雞尾酒)選擇程序來探索它是如何工做的,即便咱們選擇相同的 mocktail 兩次也會更新。程序員
目錄結構以下所示:面試
src |-> App.js |-> Mocktail.js |-> index.js |-> index.css |-> Spinner.js
咱們的程序將顯示一個被選中的 mocktail。能夠經過單擊按鈕來選擇或切換 mocktail。這時會加載一個新的 mocktail,並在加載完成後渲染出這個 mocktail 的圖像。segmentfault
App
組件的父組件有 mocktail
狀態和 updateMocktail
方法,用於處理更新 mocktail。bash
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 中的更新:
<center>沒有從 setState 返回 null</center>
<center>從 setState 返回 null 以後</center>
注意:我在這裏換了一個深色主題,以便更容易觀察到 React DOM 中的更新。
本文介紹了在 React 16 中怎樣從 setState
返回 null
。我在下面的 CodeSandbox
中添加了 mocktail
選擇程序的完整代碼,供你使用和 fork。
CodeSandbox:https://codesandbox.io/embed/...
經過使用 null
能夠防止沒必要要的狀態更新和從新渲染,這樣使咱們的程序執行得更快,從而改善程序的用戶體驗。
用戶偶然發現咱們的產品,他們對產品的見解直接反映了對公司及其產品的見解,所以咱們須要以天然和直觀的方式圍繞用戶的指望去構建體驗。
但願本文可以對你有所幫助。感謝閱讀!