Pemahaman mendalam tentang mekanisme kemas kini setState dalam React

青灯夜游
Lepaskan: 2022-01-07 19:22:59
ke hadapan
3574 orang telah melayarinya

Sebagai bahagian penting tindak balas, setState baris gilir berubah kepada keadaan komponen dan memberitahu React bahawa ia perlu memaparkan semula komponen ini dan subkomponennya dengan keadaan dikemas kini. Artikel berikut akan membawa anda melalui mekanisme setState dalam React. Saya harap ia akan membantu anda!

Pemahaman mendalam tentang mekanisme kemas kini setState dalam React

state ialah konsep penting dalam React. Kami tahu bahawa React menguruskan komponen melalui pengurusan negeri. Jadi, bagaimanakah React mengawal status komponen, dan bagaimanakah ia menggunakan status untuk mengurus komponen? [Cadangan berkaitan: Tutorial video Redis]

Kita semua tahu bahawa React mengakses this.state melalui state dan mengemas kini this.setState() melalui kaedah state. Apabila this.setState() dipanggil, React akan memanggil semula kaedah render untuk memaparkan semula UI.

setState sudah menjadi sangat biasa API kami, tetapi adakah anda benar-benar memahaminya? Di bawah ini kami akan menyahsulit mekanisme kemas kini setState bersama-sama.

setState asynchronous update

Apabila semua orang mula-mula mula menulis React, mereka biasanya menulis kod seperti this.state.value = 1, yang salah sama sekali.

Nota: Jangan sekali-kali mengubah suai ini. nyatakan ini bukan sahaja pendekatan yang tidak cekap, tetapi ia juga mungkin digantikan dengan operasi seterusnya.

setState menyedari state kemas kini melalui mekanisme baris gilir. Apabila setState dilaksanakan, state yang perlu dikemas kini akan digabungkan dan dimasukkan ke dalam baris gilir status dan bukannya mengemas kini this.state dengan segera Mekanisme baris gilir boleh mengemas kini state secara efisien dalam kelompok. Jika nilai setState diubah suai secara langsung tanpa melepasi this.state, maka state tidak akan dimasukkan ke dalam baris gilir status Apabila setState dipanggil kali seterusnya dan baris gilir status digabungkan, pengubahsuaian langsung sebelumnya akan diabaikan. Diubah suai state, menyebabkan ralat yang tidak dapat diramalkan.

Oleh itu, kaedah setState harus digunakan untuk mengemas kini state Pada masa yang sama, React juga menggunakan mekanisme baris gilir status untuk melaksanakan kemas kini tak segerak setState untuk mengelakkan kemas kini berulang yang kerap. state. Kod yang berkaitan adalah seperti berikut:

// 将新的state合并到状态更新队列中
var nextState = this._processPendingState(nextProps, nextContext);

// 根据更新队列和 shouldComponentUpdate 的状态来判断是否需要更新组件
var shouldUpdate = this._pendingForceUpdte || !inst.shouldCompoonentUpdate || inst.shouldComponentUpdate(nextProps, nextState, nextContext0;
Salin selepas log masuk

Risiko panggilan gelung setState

Apabila setState dipanggil, kaedah enqueueSetState sebenarnya akan dilaksanakan dan baris gilir akan dikemas kini untuk partialState dan _pendingStateQueue Lakukan operasi cantum, dan operasi akhir enqueueSetState melaksanakan state kemas kini.

dan kaedah performUpdateIfNecessary akan mendapat _pendingElement、_pendingStateQueue、_pendingForceUpdate dan memanggil kaedah receiveComponent dan updateComponent untuk kemas kini komponen.

Jika shouldComponetUpdate dipanggil dalam kaedah componentWillUpdate atau setState, maka this._pendingStateQueue != null, maka kaedah performUpateIfNecessary akan memanggil kaedah updateComponent untuk mengemas kini komponen, tetapi updateComponent kaedah akan Kaedah shouldComponentUpdate dan componentWillUpdate akan dipanggil, sekali gus menyebabkan gelung panggilan, menyebabkan penyemak imbas ranap apabila memori penuh.

Pemahaman mendalam tentang mekanisme kemas kini setState dalam React

setState call stack

Memandangkan setState akhirnya melaksanakan enqueueUpate kemas kini melalui state, maka bagaimanakah enqueueUpdate kemas kini state Apa tentang?

Pertama sekali, lihat soalan berikut. Bolehkah anda menjawabnya dengan betul?

import React, { Component } from 'react'

class Example extends Component {
  constructor() {
    super()
    this.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 null
  }
}
Salin selepas log masuk

Dalam kod di atas, console.log yang dicetak empat kali oleh val ialah: 0、0、2、3.

Jika hasilnya tidak betul-betul sama dengan jawapan dalam fikiran anda, maka adakah anda ingin tahu apa sebenarnya yang enqueueUpdate lakukan? Gambar di bawah ialah timbunan panggilan setState yang dipermudahkan, perhatikan pertimbangan status teras.

Pemahaman mendalam tentang mekanisme kemas kini setState dalam React

setStateTimbunan panggilan dipermudah

Menyahsulit setState

Bagaimanakah ia membawa kepada pelbagai gelagat setState yang berbeza?

我们先要了解事务跟 setState 的不同表现有什么关系。首先,我们把4次 setState 简单归类,前两次属于一类,因为他们在同一次调用栈中执行,setTimeout 中的两次 setState 属于另一类,因为他们也是在同一次调用栈中执行。我们分析一下这两类 setState 的调用栈。

componentDidMount 中直接调用的两次 setState,其调用栈更加复杂;而setTimeout 中调用的两次 setState,其调用栈则简单很多。下面我们重点看看第一类 setState 的调用栈,我们发现了 batchedUpdates 方法,原来早在 setState 调用前,已经处于batchedUpdates执行的事务中了。

batchedUpdates方法,又是谁调用的呢?我们再往前追溯一层,原来是 ReactMount.js 中的 _renderNewRootComponent方法。也就是说,整个将React组件渲染到DOM中的过程就处于一个大的事务中。

接下来的解释就顺理成章了,因为在componentDidMount中调用setState时,batchingStrategyisBatchingUpdates 已经被设为true,所以两次setState的结果并没有立即生效,而是被放到了dirtyComponents中。这也解释了两次打印 this.state.val 都是 0 的原因,因为新的 state 还没有被应用到组件中。

Pemahaman mendalam tentang mekanisme kemas kini setState dalam React

componentDidMountsetState的调用栈

Pemahaman mendalam tentang mekanisme kemas kini setState dalam React

setTimeoutsetState的调用栈

再反观 setTimeout 中的两次setState,因为没有前置的 batchedUpdate 调用,所以 batchingStrategyisBatchingUpates 标志位是false,也就导致了新的 state 马上生效,没有走到 dirtyComponents 分支。也就是说,setTimeout 中第一次执行 setState 时,this.state.val1, 而 setState 完成打印后打印时 this.state.val 变成了2。第二次的 setState 同理。

前面介绍事务时,也提到了其在 React 源码中的多处应用,像 initialize、perform、close、closeAll、motifyAll 等方法出现在调用栈中,都说明当前处于一个事务中。

既然事务这么有用,我们写应用代码时能使用它吗?很可惜,答案是不能。尽管React不建议我们直接使用事务,但在 React 15.0 之前的版本中还是为开发者提供了 batchedUpdates 方法,它可以解决针对一开始例子中setTimeout 里的两次 setState 导致两次 render 的情况:

import ReactDOM, { unstable_batchedUpates } from 'teact-dom'

unstable_batchedUpates(() => {
  this.setState(val: this.state.val + 1)
  this.setState(val: this.state.val + 1)
})
Salin selepas log masuk

React 15.0 以及之后版本中,已经彻底将 batchUpdates 这个 API 移除了,因此不再建议开发者使用它。

总结

在使用ReactsetState的过程中,了解setState的实现原理,对setState异步更新、setState循环调用风险、setState调用栈等进行更加全面的了解,才能让我们在遇到相关问题的时候更加游刃有余。

更多编程相关知识,请访问:编程入门!!

Atas ialah kandungan terperinci Pemahaman mendalam tentang mekanisme kemas kini setState dalam React. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Label berkaitan:
sumber:juejin.cn
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan
Tentang kita Penafian Sitemap
Laman web PHP Cina:Latihan PHP dalam talian kebajikan awam,Bantu pelajar PHP berkembang dengan cepat!