最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解react setState

 更新時(shí)間:2021年04月10日 11:56:29   作者:一個(gè)前端王  
這篇文章主要介紹了react setState的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)使用react,感興趣的朋友可以了解下

setState是同步還是異步

自定義合成事件和react鉤子函數(shù)中異步更新state

以在自定義click事件中的setState為例

import React, { Component } from 'react';
class Test extends Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 1
    };
  }
  handleClick = () => {
    this.setState({
      count: this.state.count + 1
    });
    this.setState({
      count: this.state.count + 1
    });
    this.setState({
      count: this.state.count + 1
    });
    console.log(this.state.count);
  }
  render() {
    return (
      <div style={{ width: '100px', height: '100px', backgroundColor: "yellow" }}>
          {this.state.count}
      </div>
    )
  }
}
export default Test;

點(diǎn)擊一次,最終this.state.count的打印結(jié)果是1,頁(yè)面展示的是2。通過(guò)現(xiàn)象看,三次setState只是最后一次setState生效了,前兩次都setState無(wú)效果。因?yàn)榧偃绨训谝淮蝧etState改為+3,count打印結(jié)果為1,展示結(jié)果為2,沒(méi)有發(fā)生變化。而且沒(méi)有同步獲得count的結(jié)果。

此時(shí),我們可以調(diào)整代碼,通過(guò)setState的第二個(gè)參數(shù),來(lái)獲得更新后的state:

import React, { Component } from 'react';
class Test extends Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 1
    };
  }
  handleClick = () => {
    this.setState({
      count: this.state.count + 3
    }, () => {
      console.log('1', this.state.count)
    });
    this.setState({
      count: this.state.count + 1
    }, () => {
      console.log('2', this.state.count);
    });
    this.setState({
      count: this.state.count + 1
    }, () => {
      console.log('3', this.state.count);
    });
    console.log(this.state.count);
  }
  render() {
    return (
      <div style={{ width: '100px', height: '100px', backgroundColor: "yellow" }}>
          {this.state.count}
      </div>
    )
  }
}
export default Test;

此時(shí),點(diǎn)擊一次,三個(gè)setState的回調(diào)函數(shù)中,打印結(jié)果分別是。

1
1: 2
2: 2
3: 2

首先,最后一行直接打印1。然后,在setState的回調(diào)中,打印出的結(jié)果都是最新更新的2。雖然前兩次setState未生效,但是它們第二個(gè)參數(shù)中還是會(huì)打印出2。

此時(shí)將setState的第一個(gè)參數(shù)換成函數(shù),通過(guò)函數(shù)的第一個(gè)參數(shù)可以獲得更新前的state。

import React, { Component } from 'react';
class Test extends Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 1
    };
  }
  handleClick = () => {
    this.setState((prevState, props) => {
      return { count: prevState.count + 1 }
    });
    this.setState((prevState, props) => {
      return { count: prevState.count + 1 }
    });
    this.setState((prevState, props) => {
      return { count: prevState.count + 1 }
    });
    console.log(this.state.count);
  }
  render() {
    return (
      <div style={{ width: '100px', height: '100px', backgroundColor: "yellow" }}>
          {this.state.count}
      </div>
    )
  }
}
export default Test;

此時(shí),打印出的結(jié)果為1,但是頁(yè)面展示出來(lái)的count為4??梢园l(fā)現(xiàn),如果setState以傳參的方式去更新state,幾次setState并不會(huì)只更新最后一次,而是幾次更新state都會(huì)生效。

接下來(lái)看下第二個(gè)函數(shù)中打印的count是多少:

import React, { Component } from 'react';
class Test extends Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 1
    };
  }
  handleClick = () => {
    this.setState((prevState, props) => {
      return { count: prevState.count + 1 }
    }, () => {
      console.log('1', this.state.count);
    });
    this.setState((prevState, props) => {
      return { count: prevState.count + 1 }
    }, () => {
      console.log('2', this.state.count);
    });
    this.setState((prevState, props) => {
      return { count: prevState.count + 1 }
    }, () => {
      console.log('3', this.state.count);
    });
    console.log(this.state.count);
  }
  render() {
    return (
      <div style={{ width: '100px', height: '100px', backgroundColor: "yellow" }}>
          {this.state.count}
      </div>
    )
  }
}
export default Test;

此時(shí),點(diǎn)擊一次,三個(gè)setState的回調(diào)函數(shù)中,打印結(jié)果如下,可想而知,頁(yè)面的展示結(jié)果也為4

1
1: 4
2: 4
3: 4

將上邊代碼放入如componentDidMount中,輸出結(jié)果跟上邊一致。

因?yàn)?,可以得知,在自定義合成事件和鉤子函數(shù)中,state的更新是異步的。

原生事件和setTimeout中同步更新state

以在setTimeout中setState為例

import React, { Component } from 'react';
class Test extends Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 1
    };
  }
  componentDidMount() {
    setTimeout(() => {
      this.setState({
        count: this.state.count + 1
      }, () => {
        console.log('1:', this.state.count);
      });
      this.setState({
        count: this.state.count + 1
      }, () => {
        console.log('2:', this.state.count);
      });
      this.setState({
        count: this.state.count + 1
      }, () => {
        console.log('3:', this.state.count);
      });
      console.log(this.state.count);
    }, 0);
  }
  render() {
    return (
      <div 
        style={{ 
          width: '100px', 
          height: '100px', 
          backgroundColor: "yellow" 
        }}>
          {this.state.count}
      </div>
    )
  }
}
export default Test;

此時(shí),打印出的結(jié)果如下:

1: 2
2: 3
3: 4
4

將setState第一個(gè)參數(shù)換為函數(shù):

componentDidMount() {
  setTimeout(() => {
    this.setState((prevState, props) => {
      return { count: prevState.count + 1 }
    }, () => {
      console.log('1', this.state.count);
    });
    this.setState((prevState, props) => {
      return { count: prevState.count + 1 }
    }, () => {
      console.log('2', this.state.count);
    });
    this.setState((prevState, props) => {
      return { count: prevState.count + 1 }
    }, () => {
      console.log('3', this.state.count);
    });
    console.log(this.state.count);
  }, 0);
}

打印出的結(jié)果和上邊一致。

是不是有一種state完全可控的感覺(jué),在setTimeout中,多次setState都會(huì)生效,而且在每一個(gè)setState的第二個(gè)參數(shù)中都可以得到更新后的state。

同樣地,在原生事件中輸出地結(jié)果和setTimeout中一致,也是同步的。

import React, { Component } from 'react';
class Test extends Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 1
    };
  }
  componentDidMount() {
    document.body.addEventListener('click', this.handleClick, false);
  }
  componentWillUnmount() {
    document.body.removeEventListener('click', this.handleClick, false);
  }
  handleClick = () => {
    this.setState((prevState, props) => {
      return { count: prevState.count + 1 }
    }, () => {
      console.log('1', this.state.count);
    });
    this.setState((prevState, props) => {
      return { count: prevState.count + 1 }
    }, () => {
      console.log('2', this.state.count);
    });
    this.setState((prevState, props) => {
      return { count: prevState.count + 1 }
    }, () => {
      console.log('3', this.state.count);
    });
    console.log(this.state.count);
  }
  render() {
    return (
      <div
        style={{ 
          width: '100px', 
          height: '100px', 
          backgroundColor: "yellow" 
        }}
      >
        {this.state.count}
      </div>
    )
  }
}
export default Test;

setState相關(guān)源碼

如下代碼均來(lái)自react17.0.2版本

目錄 ./packages/react/src/ReactBaseClasses.js

function Component(props, context, updater) {
  this.props = props;
  this.context = context;
  // If a component has string refs, we will assign a different object later.
  this.refs = emptyObject;
  // We initialize the default updater but the real one gets injected by the
  // renderer.
  this.updater = updater || ReactNoopUpdateQueue;
}

Component.prototype.isReactComponent = {};

Component.prototype.setState = function(partialState, callback) {
  invariant(
    typeof partialState === 'object' ||
      typeof partialState === 'function' ||
      partialState == null,
    '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');
};

setState可以接收兩個(gè)參數(shù),第一個(gè)參數(shù)可以是object,function,和null,undefined,就不會(huì)拋出錯(cuò)誤。執(zhí)行下邊的this.updater.enqueueSetState方法。全局查找enqueueSetState,找到兩組目錄下有這個(gè)變量。

首先是第一組目錄:

目錄 ./packages/react/src/ReactNoopUpdateQueue.js 第100行enqueueSetState方法,參數(shù)分別為this,初始化state,回調(diào),和字符串setState,this是指當(dāng)前React實(shí)例。

enqueueSetState: function(
  publicInstance,
  partialState,
  callback,
  callerName,
) {
  warnNoop(publicInstance, 'setState');
}

接著看warnNoop方法:

const didWarnStateUpdateForUnmountedComponent = {};

function warnNoop(publicInstance, callerName) {
  if (__DEV__) {
    const constructor = publicInstance.constructor;
    const componentName =
      (constructor && (constructor.displayName || constructor.name)) ||
      'ReactClass';
    const warningKey = `${componentName}.${callerName}`;
    if (didWarnStateUpdateForUnmountedComponent[warningKey]) {
      return;
    }
    console.error(
      "Can't call %s on a component that is not yet mounted. " +
        'This is a no-op, but it might indicate a bug in your application. ' +
        'Instead, assign to `this.state` directly or define a `state = {};` ' +
        'class property with the desired state in the %s component.',
      callerName,
      componentName,
    );
    didWarnStateUpdateForUnmountedComponent[warningKey] = true;
  }
}

這段代碼相當(dāng)于給didWarnStateUpdateForUnmountedComponent對(duì)象中加入屬性,屬性的key為React 當(dāng)前要setState的組件.setState,如果當(dāng)前有這個(gè)屬性則返回;如果當(dāng)前沒(méi)這個(gè)屬性或者這個(gè)屬性值為false,則設(shè)置這個(gè)屬性的值為true。

再去看另外一個(gè)目錄:

目錄 ./react-reconciler/src/ReactFiberClassComponent.new.js和ReactFiberClassComponent.old.js

const classComponentUpdater = {
  enqueueSetState(inst, payload, callback) {
    const fiber = getInstance(inst);
    const eventTime = requestEventTime();
    const lane = requestUpdateLane(fiber);

    const update = createUpdate(eventTime, lane);
    update.payload = payload;
    if (callback !== undefined && callback !== null) {
      if (__DEV__) {
        warnOnInvalidCallback(callback, 'setState');
      }
      update.callback = callback;
    }

    enqueueUpdate(fiber, update, lane);
    const root = scheduleUpdateOnFiber(fiber, lane, eventTime);
    if (root !== null) {
      entangleTransitions(root, fiber, lane);
    }

    if (__DEV__) {
      if (enableDebugTracing) {
        if (fiber.mode & DebugTracingMode) {
          const name = getComponentNameFromFiber(fiber) || 'Unknown';
          logStateUpdateScheduled(name, lane, payload);
        }
      }
    }

    if (enableSchedulingProfiler) {
      markStateUpdateScheduled(fiber, lane);
    }
  }
}

其中主要看 enqueueUpdate 這個(gè)函數(shù)

目錄 ./react-reconciler/src/ReactUpdateQueue.new.js和ReactUpdateQueue.old.js

export function enqueueUpdate<State>(
  fiber: Fiber,
  update: Update<State>,
  lane: Lane,
) {
  const updateQueue = fiber.updateQueue;
  if (updateQueue === null) {
    // Only occurs if the fiber has been unmounted.
    return;
  }

  const sharedQueue: SharedQueue<State> = (updateQueue: any).shared;

  if (isInterleavedUpdate(fiber, lane)) {
    const interleaved = sharedQueue.interleaved;
    if (interleaved === null) {
      // This is the first update. Create a circular list.
      update.next = update;
      // At the end of the current render, this queue's interleaved updates will
      // be transfered to the pending queue.
      pushInterleavedQueue(sharedQueue);
    } else {
      update.next = interleaved.next;
      interleaved.next = update;
    }
    sharedQueue.interleaved = update;
  } else {
    const pending = sharedQueue.pending;
    if (pending === null) {
      // This is the first update. Create a circular list.
      update.next = update;
    } else {
      update.next = pending.next;
      pending.next = update;
    }
    sharedQueue.pending = update;
  }

  if (__DEV__) {
    if (
      currentlyProcessingQueue === sharedQueue &&
      !didWarnUpdateInsideUpdate
    ) {
      console.error(
        'An update (setState, replaceState, or forceUpdate) was scheduled ' +
          'from inside an update function. Update functions should be pure, ' +
          'with zero side-effects. Consider using componentDidUpdate or a ' +
          'callback.',
      );
      didWarnUpdateInsideUpdate = true;
    }
  }
}

看到這里,發(fā)現(xiàn)這個(gè)方法是將此次更新的update加入到更新隊(duì)列中,而在這個(gè)版本中并沒(méi)有發(fā)現(xiàn)isBatchingUpdates這個(gè)屬性的出現(xiàn)。貌似React Fiber改動(dòng)還挺大,暫時(shí)先寫(xiě)到這里,如果有新的發(fā)現(xiàn)會(huì)補(bǔ)充到這里。

總結(jié)

  • 自定義合成事件和react鉤子函數(shù)中異步更新state
  • 原生事件和setTimeout中同步更新state

以上就是詳解react setState的詳細(xì)內(nèi)容,更多關(guān)于react setState的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 使用react render props實(shí)現(xiàn)倒計(jì)時(shí)的示例代碼

    使用react render props實(shí)現(xiàn)倒計(jì)時(shí)的示例代碼

    這篇文章主要介紹了使用react render props實(shí)現(xiàn)倒計(jì)時(shí)的示例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-12-12
  • React實(shí)現(xiàn)路由返回?cái)r截的三種方式

    React實(shí)現(xiàn)路由返回?cái)r截的三種方式

    最近項(xiàng)目為了避免用戶(hù)誤操作導(dǎo)致數(shù)據(jù)丟失,增加返回?cái)r截功能,但是之前由于qiankun的報(bào)錯(cuò)導(dǎo)致這個(gè)功能一直有一些問(wèn)題,所以專(zhuān)門(mén)獨(dú)立搞了一個(gè)專(zhuān)題研究在react中各種方式實(shí)現(xiàn)這個(gè)功能,需要的朋友可以參考下
    2024-05-05
  • 淺談React中的元素、組件、實(shí)例和節(jié)點(diǎn)

    淺談React中的元素、組件、實(shí)例和節(jié)點(diǎn)

    這篇文章主要介紹了淺談React中的元素、組件、實(shí)例和節(jié)點(diǎn),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-02-02
  • 在 React 中使用 Redux 解決的問(wèn)題小結(jié)

    在 React 中使用 Redux 解決的問(wèn)題小結(jié)

    在 React 中組件通信的數(shù)據(jù)流是單向的,頂層組件可以通過(guò) props 屬性向下層組件傳遞數(shù)據(jù),而下層組件不能直接向上層組件傳遞數(shù)據(jù),這篇文章主要介紹了使用react+redux實(shí)現(xiàn)彈出框案例,需要的朋友可以參考下
    2022-10-10
  • 解決React報(bào)錯(cuò)Expected an assignment or function call and instead saw an expression

    解決React報(bào)錯(cuò)Expected an assignment or funct

    這篇文章主要為大家介紹了React報(bào)錯(cuò)Expected an assignment or function call and instead saw an expression解決方案詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • React?Native采用Hermes熱更新打包方案詳解

    React?Native采用Hermes熱更新打包方案詳解

    這篇文章主要介紹了React?Native采用Hermes熱更新打包實(shí)戰(zhàn),在傳統(tǒng)的熱更新方案中,我們實(shí)現(xiàn)熱更新需要借助code-push開(kāi)源方案,包括熱更新包的發(fā)布兩種方式詳解,感興趣的朋友一起看看吧
    2022-05-05
  • React?中?setState?的異步操作案例詳解

    React?中?setState?的異步操作案例詳解

    這篇文章主要介紹了React中setState的異步操作案例詳解,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一點(diǎn)點(diǎn)參考價(jià)值,感興趣的小伙伴可以參考一下
    2022-08-08
  • React?中的?setState?是同步還是異步

    React?中的?setState?是同步還是異步

    這篇文章主要介紹了React?中的?setState?是同步還是異步,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2022-06-06
  • React不使用requestIdleCallback實(shí)現(xiàn)調(diào)度原理解析

    React不使用requestIdleCallback實(shí)現(xiàn)調(diào)度原理解析

    這篇文章主要為大家介紹了React不使用requestIdleCallback實(shí)現(xiàn)調(diào)度原理解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-11-11
  • React拆分窗格組件的兩種方法

    React拆分窗格組件的兩種方法

    這篇文章主要介紹了React拆分窗格組件的兩種方法,使用第三方庫(kù)react-split-pane適用于快速實(shí)現(xiàn)拆分窗格功能,并且對(duì)功能和樣式的要求較為簡(jiǎn)單的場(chǎng)景,本文結(jié)合示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-07-07

最新評(píng)論

南乐县| 南投市| 上高县| 旌德县| 宜黄县| 波密县| 蚌埠市| 锦屏县| 广平县| 汤原县| 尚义县| 邵武市| 建湖县| 高清| 余干县| 富蕴县| 怀化市| 榆社县| 蒙自县| 兴化市| 正镶白旗| 那曲县| 株洲市| 塔河县| 治县。| 全南县| 望城县| 视频| 太仓市| 昌图县| 龙南县| 德安县| 江油市| 横峰县| 柳河县| 斗六市| 高安市| 红桥区| 尖扎县| 泰安市| 顺平县|