在 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 能够防止没必要要的状态更新和从新渲染,这样使咱们的程序执行得更快,从而改善程序的用户体验。

用户偶然发现咱们的产品,他们对产品的见解直接反映了对公司及其产品的见解,所以咱们须要以天然和直观的方式围绕用户的指望去构建体验。

但愿本文可以对你有所帮助。感谢阅读!


本文首发微信公众号:前端先锋

欢迎扫描二维码关注公众号,天天都给你推送新鲜的前端技术文章

欢迎扫描二维码关注公众号,天天都给你推送新鲜的前端技术文章


欢迎继续阅读本专栏其它高赞文章:


相关文章
相关标签/搜索