在 React 16 中從 setState 返回 null 的妙用

翻譯:瘋狂的技術宅

原文:https://blog.logrocket.com/re...css

未經容許嚴禁轉載前端

概述

在 React 16 中爲了防止沒必要要的 DOM 更新,容許你決定是否讓 .setState 更來新狀態。在調用 .setState 時返回 null 將再也不觸發更新。react

咱們將經過重構一個 mocktail (一種不含酒精的雞尾酒)選擇程序來探索它是如何工做的,即便咱們選擇相同的 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 來防止來觸發更新。

解決方案

如下是咱們將要遵循的步驟,來防止沒必要要的從新渲染:

  1. 檢查新的狀態值是否與現有值相同
  2. 若是值相同,咱們將返回 null
  3. 返回 null 將不會更新狀態和觸發組件從新渲染

首先,在 app 組件的 updateMocktail 方法中,建立一個名爲 newMocktail 的常量,並用傳入的 mocktail 值爲其賦值。

updateMocktail = mocktail => {  
  const newMocktail = mocktail;    
  this.setState({     
    mocktail  
  })  
}

由於咱們須要基於以前的狀態檢查和設置狀態,而不是傳遞 setStateobject,因此咱們須要傳遞一個之前的狀態做爲參數的函數。而後檢查 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
<center>沒有從 setState 返回 null</center>

從 setState 返回 null 以後
<center>從 setState 返回 null 以後</center>

注意:我在這裏換了一個深色主題,以便更容易觀察到 React DOM 中的更新。

總結

本文介紹了在 React 16 中怎樣從 setState 返回 null。我在下面的 CodeSandbox 中添加了 mocktail 選擇程序的完整代碼,供你使用和 fork。

CodeSandbox:https://codesandbox.io/embed/...

經過使用 null 能夠防止沒必要要的狀態更新和從新渲染,這樣使咱們的程序執行得更快,從而改善程序的用戶體驗。

用戶偶然發現咱們的產品,他們對產品的見解直接反映了對公司及其產品的見解,所以咱們須要以天然和直觀的方式圍繞用戶的指望去構建體驗。

但願本文可以對你有所幫助。感謝閱讀!


本文首發微信公衆號:前端先鋒

歡迎掃描二維碼關注公衆號,天天都給你推送新鮮的前端技術文章

歡迎掃描二維碼關注公衆號,天天都給你推送新鮮的前端技術文章


歡迎繼續閱讀本專欄其它高贊文章:


相關文章
相關標籤/搜索