国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

【React進(jìn)階系列】 setState機(jī)制

Yuqi / 2512人閱讀

摘要:的批量更新優(yōu)化也是建立在異步合成事件鉤子函數(shù)之上的,在原生事件和中不會批量更新,在異步中如果對同一個值進(jìn)行多次,的批量更新策略會對其進(jìn)行覆蓋,取最后一次的執(zhí)行,如果是同時多個不同的值,在更新時會對其進(jìn)行合并批量更新。

api解析: setState(updater, [callback])
updater: 更新數(shù)據(jù) FUNCTION/OBJECT
callback: 更新成功后的回調(diào) FUNCTION
// updater - Function
this.setState((prevState, props) => {
  return {counter: prevState.counter + props.step};
});

// update - Object
this.setState({quantity: 2})
setState的特點:
1.異步:react通常會集齊一批需要更新的組件,然后一次性更新來保證渲染的性能
2.淺合并 Objecr.assign()
setState問題與解決

在使用setState改變狀態(tài)之后,立刻通過this.state去拿最新的狀態(tài)
解決: componentDidUpdate或者setState的回調(diào)函數(shù)里獲取

// setState回調(diào)函數(shù)
changeTitle: function (event) {
  this.setState({ title: event.target.value }, () => this.APICallFunction());
},
APICallFunction: function () {
  // Call API with the updated value
}

有一個需求,需要在在onClick里累加兩次,使用對象的方法更新,則只會加一次
解決: 使用updater function

onClick = () => {
    this.setState({ index: this.state.index + 1 });
    this.setState({ index: this.state.index + 1 });
}

// 最后解析為,后面的數(shù)據(jù)會覆蓋前面的更改,所以最終只加了一次.
Object.assign(
  previousState,
  {index: state.index+ 1},
  {index: state.index+ 1},
)

//正確寫法
onClick = () => {
    this.setState((prevState, props) => {
      return {quantity: prevState.quantity + 1};
    });
    this.setState((prevState, props) => {
      return {quantity: prevState.quantity + 1};
    });
}
注意:
1.不要在render()函數(shù)里面寫setstate(),除非你自己定制了shouldComponentUpdate方法,要不然會引起無限循環(huán)
render() {
    //this.setState
    return(
        //...dom
    )
}
2.為什么不能使用第一個方式更新
react為了實現(xiàn)高效render, state其實是一個隊列,setState是將數(shù)據(jù)插入隊列中,使用第一種不會觸發(fā)渲染, react提供了setState的實例方法可以觸發(fā)render,可以看后面的源碼
// 1
this.state.num = 1
// 2
this.setState({
    num: this.state.num + 1
})
3.對數(shù)組和對象等引用對象操作時,使用返回新對象的方法
  array: 不要使用push、pop、shift、unshift、splice可使用concat、slice、filter、擴(kuò)展語法
  object: Object.assgin/擴(kuò)展語法
setState更新機(jī)制

如圖: pending queue 和 update queue

setState源碼 this.setState()
ReactComponent.prototype.setState = function (partialState, callback) {
  //  將setState事務(wù)放進(jìn)隊列中
  //  this.updater就是ReactUpdateQueue, this是組件的實例
  this.updater.enqueueSetState(this, partialState);
  if (callback) {
    this.updater.enqueueCallback(this, callback, "setState");
  }
};
enqueueSetState()
enqueueSetState: function (publicInstance, partialState) {
     // 獲取當(dāng)前組件的instance
     // 實例中有兩個非常重要的屬性:_pendingStateQueue(待更新隊列) 與 _pendingCallbacks(更新回調(diào)隊列)
    var internalInstance = getInternalInstanceReadyForUpdate(publicInstance, "setState");

     // 初始化待更新隊列
     var queue = internalInstance._pendingStateQueue || (internalInstance._pendingStateQueue = []);
     // 將要更新的state放入一個數(shù)組里
    queue.push(partialState);

     //  將要更新的component instance也放在一個隊列里
    enqueueUpdate(internalInstance);
  }
enqueueUpdate
當(dāng)前如果正處于創(chuàng)建/更新組件的過程,就不會立刻去更新組件,而是先把當(dāng)前的組件放在dirtyComponent里,所以不是每一次的setState都會更新組件
function enqueueUpdate(component) {
  // 如果沒有處于批量創(chuàng)建/更新組件的階段,則處理update state事務(wù)
  if (!batchingStrategy.isBatchingUpdates) {
    batchingStrategy.batchedUpdates(enqueueUpdate, component);
    return;
  }
  // 如果正處于批量創(chuàng)建/更新組件的過程,將當(dāng)前的組件放在dirtyComponents數(shù)組中
  dirtyComponents.push(component);
}
batchingStrategy
var ReactDefaultBatchingStrategy = {
  // 用于標(biāo)記當(dāng)前是否出于批量更新
  isBatchingUpdates: false,
  // 當(dāng)調(diào)用這個方法時,正式開始批量更新
  batchedUpdates: function (callback, a, b, c, d, e) {
    var alreadyBatchingUpdates = ReactDefaultBatchingStrategy.isBatchingUpdates;

    ReactDefaultBatchingStrategy.isBatchingUpdates = true;

    // 如果當(dāng)前事務(wù)正在更新過程在中,則調(diào)用callback,既enqueueUpdate
    if (alreadyBatchingUpdates) {
      return callback(a, b, c, d, e);
    } else {
    // 否則執(zhí)行更新事務(wù)
      return transaction.perform(callback, null, a, b, c, d, e);
    }
  }
};
transaction
initalize(空函數(shù)) -> perform(anyMethos) -> close

// 將isBatchingUpdates置為false
var RESET_BATCHED_UPDATES = {
  initialize: emptyFunction,
  close: function () {
    ReactDefaultBatchingStrategy.isBatchingUpdates = false;
  }
};

// 循環(huán)所有dirtyComponent,調(diào)用updateComponent來執(zhí)行所有的生命周期方法,componentWillReceiveProps, shouldComponentUpdate, componentWillUpdate, render, componentDidUpdate 最后實現(xiàn)組件的更新
var FLUSH_BATCHED_UPDATES = {
  initialize: emptyFunction,
  close: ReactUpdates.flushBatchedUpdates.bind(ReactUpdates)
};

var TRANSACTION_WRAPPERS = [FLUSH_BATCHED_UPDATES, RESET_BATCHED_UPDATES];
setState面試
面試官:“react中setState是同步的還是異步?”
我:“異步的,setState不能立馬拿到結(jié)果。”
面試官:“那什么場景下是異步的,可不可能是同步,什么場景下又是同步的?”

下題結(jié)果是:

class App extends React.Component {
  state = { val: 0 }

  componentDidMount() {
    this.setState({ val: this.state.val + 1 })
    console.log(this.state.val)

    this.setState({ val: this.state.val + 1 })
    console.log(this.state.val)

    setTimeout(_ => {
      this.setState({ val: this.state.val + 1 })
      console.log(this.state.val);

      this.setState({ val: this.state.val + 1 })
      console.log(this.state.val)
    }, 0)
  }

  render() {
    return 
{this.state.val}
} } // 結(jié)果就為 0, 0, 2, 3
總結(jié)
1.setState 只在合成事件和鉤子函數(shù)中是“異步”的,在原生事件和 setTimeout 中都是同步的。
2.setState的“異步”并不是說內(nèi)部由異步代碼實現(xiàn),其實本身執(zhí)行的過程和代碼都是同步的,只是合成事件和鉤子函數(shù)的調(diào)用順序在更新之前,導(dǎo)致在合成事件和鉤子函數(shù)中沒法立馬拿到更新后的值,形式了所謂的“異步”,當(dāng)然可以通過第二個參數(shù) setState(partialState, callback) 中的callback拿到更新后的結(jié)果。
3.setState 的批量更新優(yōu)化也是建立在“異步”(合成事件、鉤子函數(shù))之上的,在原生事件和setTimeout 中不會批量更新,在“異步”中如果對同一個值進(jìn)行多次 setState , setState 的批量更新策略會對其進(jìn)行覆蓋,取最后一次的執(zhí)行,如果是同時 setState 多個不同的值,在更新時會對其進(jìn)行合并批量更新。
1、合成事件中的setState
合成事件,react為了解決跨平臺,兼容性問題,自己封裝了一套事件機(jī)制,代理了原生的事件,像在jsx中常見的onClick、onChange這些都是合成事件
合成事件中也有batchedUpdates方法,是通過同樣的事務(wù)完成的
class App extends Component {

  state = { val: 0 }

  increment = () => {
    this.setState({ val: this.state.val + 1 })
    console.log(this.state.val) // 輸出的是更新前的val --> 0
  }

  render() {
    return (
      
{`Counter is: ${this.state.val}`}
) } }
2、生命周期函數(shù)中的setState
整個生命周期中就是一個事物操作,所以標(biāo)識位isBatchingUpdates = true,所以流程到了enqueueUpdate()時,實例對象都會加入到dirtyComponents 數(shù)組中
class App extends Component {

  state = { val: 0 }

 componentDidMount() {
    this.setState({ val: this.state.val + 1 })
   console.log(this.state.val) // 輸出的還是更新前的值 --> 0
 }
  render() {
    return (
      
{`Counter is: ${this.state.val}`}
) } }
3、原生事件中的setState
原生事件是指非react合成事件,原生自帶的事件監(jiān)聽 addEventListener ,或者也可以用原生js、jq直接 document.querySelector().onclick 這種綁定事件的形式都屬于原生事件
原生事件綁定不會通過合成事件的方式處理,自然也不會進(jìn)入更新事務(wù)的處理流程。setTimeout也一樣,在setTimeout回調(diào)執(zhí)行時已經(jīng)完成了原更新組件流程,不會放入dirtyComponent進(jìn)行異步更新,其結(jié)果自然是同步的。
class App extends Component {

  state = { val: 0 }

  changeValue = () => {
    this.setState({ val: this.state.val + 1 })
    console.log(this.state.val) // 輸出的是更新后的值 --> 1
  }

 componentDidMount() {
    document.body.addEventListener("click", this.changeValue, false)
 }
 
  render() {
    return (
      
{`Counter is: ${this.state.val}`}
) } }
4、setTimeout中的setState

基于event loop的模型下, setTimeout 中里去 setState 總能拿到最新的state值。

class App extends Component {

  state = { val: 0 }

 componentDidMount() {
    setTimeout(_ => {
      this.setState({ val: this.state.val + 1 })
      console.log(this.state.val) // 輸出更新后的值 --> 1
    }, 0)
 }

  render() {
    return (
      
{`Counter is: ${this.state.val}`}
) } }
5、批量更新

在 setState 的時候react內(nèi)部會創(chuàng)建一個 updateQueue ,通過 firstUpdate 、 lastUpdate 、 lastUpdate.next 去維護(hù)一個更新的隊列,在最終的 performWork 中,相同的key會被覆蓋,只會對最后一次的 setState 進(jìn)行更新

class App extends Component {

  state = { val: 0 }

  batchUpdates = () => {
    this.setState({ val: this.state.val + 1 })
    this.setState({ val: this.state.val + 1 })
    this.setState({ val: this.state.val + 1 })
 }

  render() {
    return (
      
{`Counter is ${this.state.val}`} // 1
) } }

引發(fā)感想來源:

https://juejin.im/post/5b45c5...

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/98697.html

相關(guān)文章

  • setState異步、同步與進(jìn)階

    摘要:根本原因在于,并不是真正意義上的異步操作,它只是模擬了異步的行為。而合成事件和生命周期函數(shù)中,是受控制的,其會將設(shè)置為,從而走的是類似異步的那一套。總結(jié)此處總結(jié)是直接引用了只在合成事件和鉤子函數(shù)中是異步的,在原生事件和中都是同步的。 如何使用setState 在 React 日常的使用中,一個很重要的點就是,不要直接去修改 state。例如:this.state.count = 1是無...

    widuu 評論0 收藏0
  • React 深入系列4:組件的生命周期

    摘要:因為是深入系列文章,本文不會仔細(xì)介紹每個生命周期方法的使用,而是會重點講解在使用組件生命周期時,經(jīng)常遇到的疑問和錯誤使用方式。父組件發(fā)生更新導(dǎo)致的組件更新,生命周期方法的調(diào)用情況同上所述。 文:徐超,《React進(jìn)階之路》作者授權(quán)發(fā)布,轉(zhuǎn)載請注明作者及出處 React 深入系列4:組件的生命周期 React 深入系列,深入講解了React中的重點概念、特性和模式等,旨在幫助大家加深...

    warnerwu 評論0 收藏0
  • React 深入系列3:Props 和 State

    摘要:當(dāng)真正執(zhí)行狀態(tài)修改時,依賴的并不能保證是最新的,因為會把多次的修改合并成一次,這時,還是等于這幾次修改發(fā)生前的。下篇預(yù)告深入系列組件的生命周期新書推薦進(jìn)階之路作者徐超畢業(yè)于浙江大學(xué),碩士,資深前端工程師,長期就職于能源物聯(lián)網(wǎng)公司遠(yuǎn)景智能。 文:徐超,《React進(jìn)階之路》作者授權(quán)發(fā)布,轉(zhuǎn)載請注明作者及出處 React 深入系列3:Props 和 State React 深入系列,深...

    endiat 評論0 收藏0
  • React進(jìn)階系列】手寫實現(xiàn)react-redux api

    簡介:簡單實現(xiàn)react-redux基礎(chǔ)api react-redux api回顧 把store放在context里,所有子組件可以直接拿到store數(shù)據(jù) 使組件層級中的 connect() 方法都能夠獲得 Redux store 根組件應(yīng)該嵌套在 中 ReactDOM.render( , rootEl ) ReactDOM.render( ...

    劉玉平 評論0 收藏0
  • JavaScript - 收藏集 - 掘金

    摘要:插件開發(fā)前端掘金作者原文地址譯者插件是為應(yīng)用添加全局功能的一種強(qiáng)大而且簡單的方式。提供了與使用掌控異步前端掘金教你使用在行代碼內(nèi)優(yōu)雅的實現(xiàn)文件分片斷點續(xù)傳。 Vue.js 插件開發(fā) - 前端 - 掘金作者:Joshua Bemenderfer原文地址: creating-custom-plugins譯者:jeneser Vue.js插件是為應(yīng)用添加全局功能的一種強(qiáng)大而且簡單的方式。插....

    izhuhaodev 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<