日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

react中如何正确使用setState(附例子)

發(fā)布時(shí)間:2024/8/26 综合教程 52 生活家
生活随笔 收集整理的這篇文章主要介紹了 react中如何正确使用setState(附例子) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

概述

setState中對(duì)于某個(gè)state多次修改,只執(zhí)行一次(最后一次),所以可以將修改放在同一次中

import React, {Component} from 'react';

class Demotest extends Component {
  constructor(props) {
    super(props);
    this.state = {
      number: 1
    };
  }

  componentDidMount() {
    this.setState({ number: this.state.number + 1 });
     
  }

  addNumber(e) {
    this.setState({ number: this.state.number + 1 });
    this.setState({ number: this.state.number + 1 });
    this.setState({ number: this.state.number + 1 });
    console.log(this.state.number);
  }

  render() {
    return (
      <div>
        <div>
          <span>當(dāng)前數(shù)字是{this.state.number}</span>
        </div>

        <br/>
        <div>
          <button onClick={e => {
            this.addNumber(e);
          }}>點(diǎn)擊添加
          </button>
        </div>

      </div>
    );
  }
}

export default Demotest;

初始加載后

這時(shí)發(fā)現(xiàn)頁面上顯示的是2,控制臺(tái)輸出的卻是1,按道理 componentDidMount?里的應(yīng)該已經(jīng)成功了,不然不會(huì)顯示2,那為什么控制臺(tái)輸出的卻是1 呢?

由于 setState?是異步的所以,所以同步代碼執(zhí)行結(jié)束后才會(huì)執(zhí)行,所以在 console.log('componentDidMount: ', this.state.number);? 執(zhí)行的時(shí)候 state?還沒有被改變,所以生命周期里的輸出還是原來的值。
此時(shí)我們點(diǎn)擊按鈕,觸發(fā)函數(shù) addNumber? 發(fā)現(xiàn),函數(shù)里的三次 setState?只生效了一次 ,頁面顯示的數(shù)字變成了3,控制臺(tái)輸出了**2?**(對(duì)應(yīng)上面代碼20行),這是因?yàn)槎啻胃卤缓喜ⅲ惒降脑驅(qū)е轮惠敵隽?。官方文檔上明確說明,如果希望通過這里的狀態(tài)更新一下個(gè)狀態(tài),需要在 setState?中使用函數(shù)來取得

  addNumber(e) {
    this.setState((nextState) => {
      console.log(nextState.number);
      return { number: nextState.number + 1 };
    });

    this.setState((nextState) => {
      console.log(nextState.number);
      return { number: nextState.number + 1 };
    });

    this.setState((nextState) => {
      console.log(nextState.number);
      return { number: nextState.number + 1 };
    });
  }

此時(shí)輸出的是2、3、4

這里要說明的是當(dāng)你在 ****willMount**?前設(shè)進(jìn)行 state?的設(shè)置不會(huì) render?的觸發(fā),而事件和可以 componentDidMount?觸發(fā) render?, 而且原生的事件可以優(yōu)先這個(gè)機(jī)制

  componentDidMount() {
    document.body.addEventListener('click', this.updateData, false);
  }

  updateData = () => {
    this.setState({
      number: this.state.number + 1
    });
    console.log('componentDidMount: ', this.state.number);
  };

詳解setState

上面概述了下setState會(huì)出現(xiàn)的'合并',下面引用官網(wǎng)的一段話

setState() 將對(duì)組件 state 的更改排入隊(duì)列,并通知 React 需要使用更新后的 state 重新渲染此組件及其子組件。這是用于更新用戶界面以響應(yīng)事件處理器和處理服務(wù)器數(shù)據(jù)的主要方式
setState() 視為_請(qǐng)求_而不是立即更新組件的命令。為了更好的感知性能,React 會(huì)延遲調(diào)用它,然后通過一次傳遞更新多個(gè)組件。React 并不會(huì)保證 state 的變更會(huì)立即生效。
setState() 并不總是立即更新組件。它會(huì)批量推遲更新。這使得在調(diào)用 setState() 后立即讀取 this.state 成為了隱患。為了消除隱患,請(qǐng)使用 componentDidUpdate 或者 setState 的回調(diào)函數(shù)(setState(updater, callback)),這兩種方式都可以保證在應(yīng)用更新后觸發(fā)。如需基于之前的 state 來設(shè)置當(dāng)前的 state,請(qǐng)閱讀下述關(guān)于參數(shù) updater 的內(nèi)容。
除非 shouldComponentUpdate() 返回 false,否則 setState() 將始終執(zhí)行重新渲染操作。如果可變對(duì)象被使用,且無法在 shouldComponentUpdate() 中實(shí)現(xiàn)條件渲染,那么僅在新舊狀態(tài)不一時(shí)調(diào)用 setState()可以避免不必要的重新渲染


下面通過幾個(gè)例子分析setState在實(shí)際應(yīng)用中的運(yùn)用和注意點(diǎn)

附上一段源碼

Component.prototype.setState = function(partialState, callback) {
  // 校驗(yàn)是否符合三種情況
  invariant(
    typeof partialState === 'object' ||
      typeof partialState === 'function' ||
      partialState == null,
    // 接受狀態(tài)變量的對(duì)象以進(jìn)行更新或者通過函數(shù)返回狀態(tài)變量的對(duì)象
    'setState(...): takes an object of state variables to update or a ' +
      'function which returns an object of state variables.',
  );
  this.updater.enqueueSetState(this, partialState, callback, 'setState');
};
  enqueueSetState: function (publicInstance, partialState) {
    if (process.env.NODE_ENV !== 'production') {
      ReactInstrumentation.debugTool.onSetState();
      process.env.NODE_ENV !== 'production' ? warning(partialState != null, 'setState(...): You passed an undefined or null state object; ' + 'instead, use forceUpdate().') : void 0;
    }

    var internalInstance = getInternalInstanceReadyForUpdate(publicInstance, 'setState');

    if (!internalInstance) {
      return;
    }

    var queue = internalInstance._pendingStateQueue || (internalInstance._pendingStateQueue = []);
    queue.push(partialState);

    enqueueUpdate(internalInstance);
  }
function enqueueUpdate(internalInstance) {
  ReactUpdates.enqueueUpdate(internalInstance);
}

function enqueueUpdate(component) {
  ensureInjected();

  // Various parts of our code (such as ReactCompositeComponent's
  // _renderValidatedComponent) assume that calls to render aren't nested;
  // verify that that's the case. (This is called by each top-level update
  // function, like setState, forceUpdate, etc.; creation and
  // destruction of top-level components is guarded in ReactMount.)

  // 是批處理更新, 默認(rèn)為false
  if (!batchingStrategy.isBatchingUpdates) {
    batchingStrategy.batchedUpdates(enqueueUpdate, component);
    return;
  }

  dirtyComponents.push(component);
  if (component._updateBatchNumber == null) {
    component._updateBatchNumber = updateBatchNumber + 1;
  }
}

setState的第一個(gè)參數(shù)

// 官網(wǎng)的api ---> 第一個(gè)參數(shù)可以是對(duì)象或者一個(gè)函數(shù)
setState(updater, [callback])

如果傳入的是對(duì)象則會(huì)淺層合并到新的 state 中,后調(diào)用的?setState()?將覆蓋同一周期內(nèi)先調(diào)用?setState?的值

Object.assign(
  previousState,
  {quantity: state.quantity + 1},
  {quantity: state.quantity + 1},
  ...
)

相當(dāng)于同個(gè)屬性被合并。

如果第一個(gè)參數(shù)是函數(shù),形式如下

(state, props) => stateChange

函數(shù)中接收的?state?和?props?都保證為最新, 是你的上次setState的狀態(tài)值。

具體例子

import React, { Component } from 'react';
class App extends Component {
  constructor(props) {
    super(props)
    this.state = {
      number: 0
    }
  }
  
  // 運(yùn)行一遍,不理解的對(duì)照注釋看 
	 add () {
    // 進(jìn)入隊(duì)列 number: 0 + 222 = 222
    this.setState({
      number: this.state.number + 222
    })

    // 進(jìn)入隊(duì)列 number: 0 + 5 =5
     this.setState({
      number: this.state.number + 5
    })

    // 進(jìn)入隊(duì)列 number: 5 + 1 = 6
    this.setState((state, props) => {
      // 此時(shí)state是上次setState中的number ==>  5
      console.log('one', state);
      return {
        number: state.number + 1
      }
    })

    // 進(jìn)入隊(duì)列 number: 0 + 1 = 1
    this.setState({
      number: this.state.number + 1
    })

    // 進(jìn)入隊(duì)列: 1 + 2 = 3
    this.setState((state, props) => {
      // 此時(shí)state是上次setState中的number ==> 1
      console.log('two', state);
      return {
        number: state.number + 2
      }
    })

    // 進(jìn)入隊(duì)列: 3 + 1 = 4
    this.setState((state, props) => {
      // 此時(shí)state是上次setState中的number ==> 3
      console.log('three', state);
      return {
        number: state.number + 1
      }
    })
  }
  render () {
    return (
      <div>
        <button onClick={e =>{this.add()}}>add</button>
        {this.state.number}
      </div>
    );
  }
}

export default App;

輸出分別為 5 、 1 、? 3,最后頁面顯示的是4。

第二個(gè)參數(shù)

setState()?的第二個(gè)參數(shù)為可選的回調(diào)函數(shù),它將在?setState?完成合并并重新渲染組件后執(zhí)行。通常,我們建議使用?componentDidUpdate()?來代替此方式。

考慮如下場(chǎng)景:
在同個(gè)組件中一個(gè)具有進(jìn)度條的頁面需要不停的加載請(qǐng)求,只有當(dāng)某次請(qǐng)求正確返回?cái)?shù)據(jù)后出現(xiàn)新的內(nèi)容區(qū)域。當(dāng)數(shù)據(jù)返回后你將進(jìn)度條比例設(shè)置為100,同時(shí)設(shè)置數(shù)據(jù)到state上。

this.ajax() {
	this.$post(xxx.com)
    .then(res => {
  		this.setState({
      	progress: 100,
        data: res
      })
  	})
    .catch(err => {console.log(err)}) 
}

設(shè)置為100%是為了數(shù)據(jù)到來后進(jìn)度條立馬拉滿,然后在渲染對(duì)應(yīng)的數(shù)據(jù)內(nèi)容區(qū)域,這樣寫會(huì)出現(xiàn)進(jìn)度條其實(shí)也拉滿了,但是視覺效果沒出來數(shù)據(jù)內(nèi)容區(qū)域就出來的情況。所以用到第二個(gè)參數(shù)

this.ajax() {
	this.$post(xxx.com)
    .then(res => {
  		this.setState({
      	progress: 100,
      }, () => {
      	this.setState({
          data: res
        })
      })
  	})
    .catch(err => {console.log(err)}) 
}

總結(jié)

以上是生活随笔為你收集整理的react中如何正确使用setState(附例子)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。