NextTick คืออะไรหรือทำอะไรใน VueJs


121

ฉันอ่านเอกสาร แต่ไม่เข้าใจ ฉันรู้ว่าข้อมูลใดคำนวณดูวิธีการทำ แต่สิ่งที่nextTick()ใช้สำหรับ vuejs?


21
แนวคิดที่สำคัญจะเข้าใจได้ว่า DOM ที่มีการปรับปรุงแบบไม่พร้อมกัน เมื่อคุณเปลี่ยนค่าในวูเปลี่ยนแปลงไม่ได้ทันทีให้กับ DOM แต่ Vue จะจัดคิวการอัปเดต DOM จากนั้นในตัวจับเวลาจะอัปเดต DOM โดยปกติสิ่งนี้จะเกิดขึ้นเร็วมากจนไม่ได้สร้างความแตกต่าง แต่ในบางครั้งคุณต้องอัปเดต DOM ที่แสดงผลหลังจากที่ Vue แสดงผลแล้วซึ่งคุณไม่สามารถทำได้ทันทีในวิธีการเนื่องจากการอัปเดตยังไม่เกิดขึ้น ยัง. nextTickในกรณีที่คุณจะใช้ เอกสารที่นี่
เบิร์ต

เพื่อเติมเต็มสิ่งที่ @Bert พูดในhttps://stackoverflow.com/q/47634258/9979046ด้านบน nextTick () จะถูกใช้ในการทดสอบหน่วยเมื่อคุณต้องการตรวจสอบว่ามีองค์ประกอบใน DOM (HTML) หรือไม่เช่น หากคุณได้รับข้อมูลบางอย่างเกี่ยวกับคำขอของ Axios
Oscar Alencar

ทำไมฉันรู้สึกว่า nextTick เป็นอย่างนั้นconst nextTick = (callback, context) => { setTimeout(callback.bind(context), 0); };?
SparK

คำตอบ:


155

nextTickช่วยให้คุณสามารถทำบางสิ่งได้หลังจากที่คุณเปลี่ยนข้อมูลและ VueJS ได้อัปเดต DOM ตามการเปลี่ยนแปลงข้อมูลของคุณ แต่ก่อนที่เบราว์เซอร์จะแสดงการเปลี่ยนแปลงเหล่านั้นบนหน้า

โดยปกติdevs ใช้ฟังก์ชัน JavaScript ดั้งเดิม setTimeoutเพื่อให้ได้ลักษณะการทำงานที่คล้ายคลึงกัน แต่การใช้การsetTimeoutยกเลิกการควบคุมไปยังเบราว์เซอร์ก่อนที่จะให้การควบคุมกลับมาหาคุณผ่านการโทรกลับของคุณ

สมมติว่าคุณเปลี่ยนข้อมูลบางส่วน Vue อัปเดต DOM ตามข้อมูล โปรดทราบว่าเบราว์เซอร์ยังไม่แสดงการเปลี่ยนแปลง DOM บนหน้าจอ หากคุณใช้ระบบnextTickจะโทรกลับทันที จากนั้นเบราว์เซอร์จะอัปเดตเพจ หากคุณใช้การsetTimeoutโทรกลับของคุณจะถูกโทรหาในตอนนี้เท่านั้น

คุณสามารถเห็นภาพพฤติกรรมนี้ได้โดยการสร้างส่วนประกอบเล็ก ๆ ดังต่อไปนี้:

<template>
  <div class="hello">
    {{ msg }}
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  data() {
    return {
        msg: 'One'
    }
  },
  mounted() {
      this.msg = 'Two';

      this.$nextTick(() => {
          this.msg = 'Three';
      });
  }
}
</script>

เรียกใช้เซิร์ฟเวอร์ภายในของคุณ คุณจะเห็นข้อความThreeถูกแสดง

ตอนนี้แทนที่ของคุณthis.$nextTickด้วยsetTimeout

setTimeout(() => {
    this.msg = 'Three';
}, 0);

โหลดเบราว์เซอร์ใหม่ คุณจะเห็นก่อนที่คุณจะเห็นTwoThree

ตรวจสอบซอนี้เพื่อดูสด

นั่นเป็นเพราะ Vue อัปเดต DOM เป็นTwoให้การควบคุมเบราว์เซอร์ เบราว์เซอร์ปรากฏTwoขึ้น จากนั้นโทรกลับ Vue อัปเดต DOM เป็นThree. ซึ่งเบราว์เซอร์แสดงอีกครั้ง.

ด้วยnextTick. Vue udpated DOM เป็นTwo. โทรกลับของคุณ Vue อัปเดต DOM เป็นThree. จากนั้นให้การควบคุมเบราว์เซอร์ และเบราว์เซอร์จะปรากฏThreeขึ้น

หวังว่ามันจะชัดเจน

เพื่อให้เข้าใจถึงวิธีการดำเนิน Vue นี้คุณต้องเข้าใจแนวคิดของเหตุการณ์ห่วงและmicrotasks

เมื่อคุณมีแนวคิดเหล่านี้ชัดเจน (ER), ตรวจสอบรหัสแหล่งสำหรับ nextTick


4
สิ่งหนึ่งที่ฉันไม่เข้าใจคือเมื่อคุณพูดว่า "vue อัปเดตข้อมูล" คุณกำลังอ้างถึงการอัปเดตที่สร้างขึ้นจาก ex: this.name = 'foo'หรือคุณกำลังอ้างถึงการแทรกองค์ประกอบ html ในหน้า?
hidar

1
ฉันไม่เห็นที่ใดในประวัติของคำถามนี้ที่เขาพูดว่า "vue อัปเดตข้อมูล" ... เขาพูดว่า "Vue อัปเดต DOM ตามข้อมูล" ซึ่งหมายความว่าเมื่อคุณตั้งค่าข้อมูลผ่านthis.name = 'foo'vue จะอัปเดตโมเดลอ็อบเจ็กต์เอกสารเพื่อแสดงถึงการเปลี่ยนแปลงที่เกิดขึ้นกับข้อมูลตามเทมเพลตและฟังก์ชันที่คุณกำหนดค่า
ADJenks

31

เนื้อหานี้นำมาจาก By Adrià Fontcuberta

เอกสาร Vue กล่าวว่า:

Vue.nextTick ([เรียกกลับบริบท])

เลื่อนการเรียกกลับเพื่อดำเนินการหลังจากรอบการอัปเดต DOM ถัดไป ใช้ทันทีหลังจากที่คุณเปลี่ยนข้อมูลบางส่วนเพื่อรอการอัปเดต DOM

อืม ... ถ้าตอนแรกรู้สึกกลัวก็ไม่ต้องกังวลฉันจะพยายามอธิบายให้เรียบง่ายที่สุด แต่ก่อนอื่นมี 2 สิ่งที่คุณควรรู้:

  1. การใช้งานมันผิดปกติ เช่นเดียวกับหนึ่งในการ์ดเวทมนตร์สีเงินเหล่านั้น ฉันเขียนVueแอพหลายตัวแล้วและเจอ nextTick () หนึ่งครั้งหรือสองครั้ง

  2. เข้าใจง่ายขึ้นเมื่อคุณได้เห็นกรณีการใช้งานจริง หลังจากที่คุณได้แนวคิดแล้วความกลัวจะหายไปและคุณจะมีเครื่องมือที่มีประโยชน์อยู่ใต้เข็มขัดของคุณ

ไปกันเลยดีกว่า

ทำความเข้าใจกับ $ nextTick

เราเป็นโปรแกรมเมอร์ไม่ใช่เหรอ? เราจะใช้วิธีการแบ่งแยกและพิชิตอันเป็นที่รักของเราเพื่อพยายามแปลคำอธิบายที.nextTick()ละนิด เริ่มต้นด้วย:

เลื่อนการโทรกลับ

ตกลงตอนนี้เรารู้แล้วว่ายอมรับการติดต่อกลับ จึงมีลักษณะดังนี้:

Vue.nextTick(function () {
  // do something cool
});

เยี่ยมมาก การโทรกลับนี้ถูกเลื่อนออกไป (นี่คือสิ่งที่คนนับพันปีพูดว่าล่าช้า) จนถึง ...

รอบการอัปเดต DOM ถัดไป

ตกลง. เรารู้ว่าวูดำเนินการปรับปรุง DOM ถ่ายทอดสด คุณลักษณะนี้มีวิธีการ "จัดเก็บ" การอัปเดตเหล่านี้ไว้จนกว่าจะจำเป็นต้องใช้ สร้างคิวการอัปเดตและล้างข้อมูลเมื่อจำเป็น จากนั้น DOM จะถูก "แก้ไข" และอัปเดตเป็นเวอร์ชันล่าสุด

อะไร?

ให้ฉันลองอีกครั้ง: ลองนึกภาพส่วนประกอบของคุณทำบางสิ่งที่สำคัญและชาญฉลาดเช่นthis.potatoAmount = 3.Vue จะไม่แสดงผลส่วนประกอบอีกครั้ง (และ DOM) โดยอัตโนมัติ มันจะจัดคิวการแก้ไขที่จำเป็น จากนั้นใน "ติ๊ก" ถัดไป (เช่นเดียวกับนาฬิกา) คิวจะถูกล้างและการอัปเดตจะถูกนำไปใช้ ธาดา!

ตกลง! ดังนั้นเราจึงรู้ว่าเราสามารถใช้nextTick()เพื่อส่งผ่านฟังก์ชันการเรียกกลับที่ดำเนินการได้ทันทีหลังจากตั้งค่าข้อมูลและ DOM ได้รับการอัปเดต

อย่างที่บอกไปก่อนหน้านี้…ไม่บ่อยนัก แนวทาง "การไหลของข้อมูล" ที่ขับเคลื่อน Vue, React และอีกวิธีหนึ่งจาก Google ซึ่งฉันจะไม่พูดถึงทำให้มันไม่จำเป็นเกือบตลอดเวลา อย่างไรก็ตามบางครั้งเราต้องรอให้องค์ประกอบบางอย่างปรากฏ / หายไป / แก้ไขใน DOM นี่คือตอนที่ nextTick มีประโยชน์

ใช้ทันทีหลังจากที่คุณเปลี่ยนข้อมูลบางส่วนเพื่อรอการอัปเดต DOM

เป๊ะ! นี่คือคำจำกัดความชิ้นสุดท้ายที่ Vue docs ให้กับเรา ภายในการโทรกลับของเรา DOM ได้รับการอัปเดตเพื่อให้เราสามารถโต้ตอบกับเวอร์ชันที่ "อัปเดตที่สุด" ได้

พิสูจน์สิ

ตกลงตกลง. ดูคอนโซลและคุณจะเห็นว่าค่าของข้อมูลของเราได้รับการอัปเดตภายในการเรียกกลับของ nextTick เท่านั้น:

const example = Vue.component('example', {
  template: '<p>{{ message }}</p>',
  data: function () {
    return {
      message: 'not updated'
    }
  },
  mounted () {
    this.message = 'updated'

        console.log(
        'outside nextTick callback:', this.$el.textContent
    ) // => 'not updated'

    this.$nextTick(() => {
      console.log(
        'inside nextTick callback:', this.$el.textContent
      ) // => 'not updated'
    })
  }
})


new Vue({
  el: '#app',
    render: h => h(example)
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.10/vue.js"></script>
<div id="app"></div>

กรณีการใช้งาน

nextTickลองที่จะกำหนดกรณีการใช้งานบางอย่างมีประโยชน์สำหรับ

ลองนึกภาพว่าคุณต้องดำเนินการบางอย่างเมื่อต่อส่วนประกอบ แต่! ไม่เพียง แต่ส่วนประกอบเท่านั้น คุณต้องรอจนกว่าลูกทั้งหมดจะติดตั้งและพร้อมใช้งานใน DOM ประณาม! ขอเกี่ยวของเราไม่รับประกันว่าโครงสร้างส่วนประกอบทั้งหมดจะแสดงผล

หากเพียงเรามีเครื่องมือสำหรับรอการอัปเดต DOM รอบถัดไป ...

ฮ่าฮ่า:

mounted() {
  this.$nextTick(() => {
    // The whole view is rendered, so I can safely access or query
    // the DOM. ¯\_(ツ)_/¯
  })
}

โดยสังเขป

ดังนั้น: nextTickเป็นวิธีที่สะดวกสบายในการเรียกใช้ฟังก์ชันหลังจากที่ตั้งค่าข้อมูลและ DOM ได้รับการอัปเดตแล้ว

คุณต้องรอ DOM อาจเป็นเพราะคุณต้องทำการเปลี่ยนแปลงบางอย่างหรือคุณต้องรอให้ไลบรารีภายนอกโหลดข้อมูล จากนั้นใช้ nextTick

บางคนยังใช้ nextTick ในการทดสอบหน่วยเพื่อให้แน่ใจว่าข้อมูลได้รับการอัปเดตแล้ว ด้วยวิธีนี้พวกเขาสามารถทดสอบ "เวอร์ชันอัปเดต" ของคอมโพเนนต์

Vue.nextTick () หรือ vm. $ nextTick ()?

ไม่ต้องกังวล. ทั้งสอง (เกือบ) เหมือนกัน Vue.nextTick()หมายถึงวิธีการ API ส่วนกลางในขณะที่vm.$nextTick()เป็นวิธีการอินสแตนซ์ ข้อแตกต่างเพียงอย่างเดียวคือvm.$nextTickไม่ยอมรับบริบทเป็นพารามิเตอร์ที่สอง มันถูกผูกไว้กับthis(หรือที่เรียกว่าอินสแตนซ์เอง)

ชิ้นสุดท้ายของความเย็น

สังเกตว่าnextTickส่งกลับ a Promiseเพื่อให้เราสามารถใช้async/awaitและปรับปรุงตัวอย่างได้อย่างเต็มที่:

async mounted () {
    this.message = 'updated'
    console.log(this.$el.textContent) // 'not updated'
    await this.$nextTick()
    console.log(this.$el.textContent) // 'updated'
}

4
เพียงเพิ่มผู้แต่งต้นฉบับและลิงก์ที่ด้านบนของคำอธิบาย "ของคุณ"
Renan Cidale

1
เป็นคำอธิบายที่น่าทึ่งจริงๆ! ขอบคุณมากสำหรับเวลาและความพยายามของคุณ
Muaath Alhaddad

ให้ตายเถอะคุณแค่คัดลอกโพสต์ขนาดกลางทั้งหมด โหวตลดลง
Alexander Kim

เมื่อนักพัฒนาค้นหาคำตอบในStackOverflowผลลัพธ์ของ Google มักจะเป็นอันดับแรก SO เป็นสถานที่สำหรับค้นหาคำตอบโดยพฤตินัย แต่มีแหล่งข้อมูลดีๆมากมายบนอินเทอร์เน็ตซึ่งอาจไม่ปรากฏในผลการค้นหา ดังนั้นฉันจึงใช้เวลาเกือบครึ่งชั่วโมงสำหรับคำตอบนี้ไม่ใช่แค่การคัดลอกตามที่คุณระบุผู้เขียนได้รับเครดิตตั้งแต่เริ่มต้น ถ้าไม่ชอบโพสต์ก็โอเค แต่คุณควรเคารพงานของผู้อื่น
Humoyun Ahmad

1
ฮ่า ๆ ๆ ฉันสบายดีที่มีการคัดลอกโพสต์ตราบใดที่ผู้คนเข้าใจว่า nextTick ทำงานอย่างไร (และลิงก์ย้อนกลับไม่เจ็บ!);)
afontcu

16

Next Tick โดยทั่วไปจะช่วยให้คุณสามารถรันโค้ดได้หลังจากที่ vue แสดงผลคอมโพเนนต์อีกครั้งเมื่อคุณทำการเปลี่ยนแปลงบางอย่างกับคุณสมบัติรีแอคทีฟ (ข้อมูล)

// modify data
vm.msg = 'Hello'
// DOM not updated yet
Vue.nextTick(function () {
  // this function is called when vue has re-rendered the component.
})

// usage as a promise (2.1.0+, see note below)
Vue.nextTick()
  .then(function () {
      // this function is called when vue has re-rendered the component.
})

จากเอกสาร Vue.js:

เลื่อนการเรียกกลับเพื่อดำเนินการหลังจากรอบการอัปเดต DOM ถัดไป ใช้ทันทีหลังจากที่คุณเปลี่ยนข้อมูลบางส่วนเพื่อรอการอัปเดต DOM

อ่านข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้ที่นี่


2
อัพเดตได้อย่างไร? นี่คือสิ่งที่ฉันไม่ยอมรับ ถ้าฉันอัปเดต vm.msg แล้ว dom จะได้รับการอัปเดตแล้วเนื่องจากมีข้อความใหม่ "สวัสดี" .. ฉันจะอัปเดตอีกครั้งได้อย่างไรคุณสามารถโพสต์ซอพร้อมตัวอย่างได้อย่างไรขอบคุณ
hidar

โอเคฉันจะแก้ไขคำตอบและฉันจะพยายามอธิบายเพิ่มเติม
Daksh Miglani

@hidar คุณสามารถใช้ในสถานการณ์ที่คุณต้องอัปเดตหลายรายการ แต่คุณต้องการแสดงผลซึ่งกันและกันอย่างชัดเจนในรอบโดมที่แตกต่างกัน
Daksh Miglani

ไม่อนุญาตให้คุณอัปเดต DOM ต่อตัว แต่จะทำอะไรก็ได้ (ไม่ว่าจะเป็นการอัปเดตอ่านข้อมูลจากมัน ฯลฯ ) หลังจากที่ได้รับผลกระทบ / แก้ไขจากการเปลี่ยนแปลงที่ทำโดย Vue (เนื่องจากคุณเปลี่ยนค่าคุณสมบัติที่ตอบสนอง ฯลฯ )
zenw0lf

นั่นเป็นตัวอย่างเพื่อให้ง่ายขึ้น
Daksh Miglani

7

เพื่อให้คำตอบของ Pranshat เกี่ยวกับความแตกต่างระหว่างการใช้ nextTick และ setTimeout ชัดเจนยิ่งขึ้นฉันได้แยกเสียงซอของเขา: ที่นี่

mounted() {    
  this.one = "One";
 
  setTimeout(() => {
    this.two = "Two"
  }, 0);
  
  //this.$nextTick(()=>{
  //this.two = "Two"
  //})}

คุณจะเห็นในซอว่าเมื่อใช้ setTimeOut ข้อมูลเริ่มต้นจะกะพริบสั้น ๆ เมื่อประกอบส่วนประกอบก่อนที่จะปรับการเปลี่ยนแปลง ในขณะที่เมื่อใช้ nextTick ข้อมูลจะถูกแย่งชิงเปลี่ยนแปลงก่อนที่จะแสดงผลไปยังเบราว์เซอร์ ดังนั้นเบราว์เซอร์จึงแสดงข้อมูลที่อัปเดตโดยที่ไม่มีความรู้เรื่องเก่าเลย หวังว่าจะเคลียร์ทั้งสองแนวคิดในบัดดล

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.