Watchers
Basic Example
গণনাকৃত বৈশিষ্ট্য আমাদেরকে ডিক্লেয়ারভাবে প্রাপ্ত মান গণনা করতে দেয়। যাইহোক, এমন কিছু ক্ষেত্রে আছে যেখানে রাষ্ট্রীয় পরিবর্তনের প্রতিক্রিয়ায় আমাদের "পার্শ্ব প্রতিক্রিয়া" করতে হবে - উদাহরণস্বরূপ, DOM পরিবর্তন করা, বা অ্যাসিঙ্ক অপারেশনের ফলাফলের ভিত্তিতে রাষ্ট্রের অন্য অংশ পরিবর্তন করা।
কম্পোজিশন এপিআই-এর সাথে, যখনই প্রতিক্রিয়াশীল অবস্থার একটি অংশ পরিবর্তিত হয় তখন আমরা একটি কলব্যাক ট্রিগার করতে ওয়াচ
ফাংশন ব্যবহার করতে পারি:
vue
<script setup>
import { ref, watch } from 'vue'
const question = ref('')
const answer = ref('Questions usually contain a question mark. ;-)')
const loading = ref(false)
// watch works directly on a ref
watch(question, async (newQuestion, oldQuestion) => {
if (newQuestion.includes('?')) {
loading.value = true
answer.value = 'Thinking...'
try {
const res = await fetch('https://yesno.wtf/api')
answer.value = (await res.json()).answer
} catch (error) {
answer.value = 'Error! Could not reach the API. ' + error
} finally {
loading.value = false
}
}
})
</script>
<template>
<p>
Ask a yes/no question:
<input v-model="question" :disabled="loading" />
</p>
<p>{{ answer }}</p>
</template>
Watch Source Types
watch
এর প্রথম যুক্তি হতে পারে বিভিন্ন ধরনের প্রতিক্রিয়াশীল "উৎস": এটি একটি ref (including computed refs), একটি প্রতিক্রিয়াশীল অবজেক্ট, একটি getter ফাংশন, বা একাধিক sources একটি array হতে পারে:
js
const x = ref(0)
const y = ref(0)
// single ref
watch(x, (newX) => {
console.log(`x is ${newX}`)
})
// getter
watch(
() => x.value + y.value,
(sum) => {
console.log(`sum of x + y is: ${sum}`)
}
)
// array of multiple sources
watch([x, () => y.value], ([newX, newY]) => {
console.log(`x is ${newX} and y is ${newY}`)
})
মনে রাখবেন যে আপনি এই মত একটি প্রতিক্রিয়াশীল অবজেক্টর একটি কম্পিউটেড প্রপার্টি দেখতে পারবেন না:
js
const obj = reactive({ count: 0 })
// this won't work because we are passing a number to watch()
watch(obj.count, (count) => {
console.log(`count is: ${count}`)
})
পরিবর্তে, একটি গেটার ব্যবহার করুন:
js
// instead, use a getter:
watch(
() => obj.count,
(count) => {
console.log(`count is: ${count}`)
}
)
Deep Watchers
যখন আপনি একটি প্রতিক্রিয়াশীল অবজেক্টতে সরাসরি watch()
কল করেন, তখন এটি অন্তর্নিহিতভাবে একটি গভীর পর্যবেক্ষণকারী তৈরি করবে - কলব্যাকটি সমস্ত নেস্টেড মিউটেশনে ট্রিগার হবে:
js
const obj = reactive({ count: 0 })
watch(obj, (newValue, oldValue) => {
// fires on nested property mutations
// Note: `newValue` will be equal to `oldValue` here
// because they both point to the same object!
})
obj.count++
এটি একটি প্রাপ্তকারীর সাথে পার্থক্য করা উচিত যা একটি প্রতিক্রিয়াশীল অবজেক্ট ফেরত দেয় - পরবর্তী ক্ষেত্রে, কলব্যাক শুধুমাত্র তখনই চালু হবে যদি প্রাপ্তকারী একটি ভিন্ন অবজেক্ট ফেরত দেয়:
js
watch(
() => state.someObject,
() => {
// fires only when state.someObject is replaced
}
)
তবে, আপনি স্পষ্টভাবে deep
বিকল্পটি ব্যবহার করে দ্বিতীয় কেসটিকে গভীর পর্যবেক্ষণকারীতে জোর করতে পারেন:
js
watch(
() => state.someObject,
(newValue, oldValue) => {
// Note: `newValue` will be equal to `oldValue` here
// *unless* state.someObject has been replaced
},
{ deep: true }
)
সতর্কতার সাথে ব্যবহার করুন
গভীর ওয়াচর জন্য প্রেক্ষিত অবজেক্টর সমস্ত নেস্টেড বৈশিষ্ট্যগুলিকে অতিক্রম করা প্রয়োজন এবং বড় ডেটা স্ট্রাকচারে ব্যবহার করা হলে এটি ব্যয়বহুল হতে পারে। প্রয়োজন হলেই এটি ব্যবহার করুন এবং কর্মক্ষমতার প্রভাব সম্পর্কে সতর্ক থাকুন।
Eager Watchers
watch
ডিফল্টরূপে অলস: দেখা উৎস পরিবর্তন না হওয়া পর্যন্ত কলব্যাক কল করা হবে না। কিন্তু কিছু ক্ষেত্রে আমরা একই কলব্যাক লজিক সাগ্রহে চালিত করতে চাই - উদাহরণস্বরূপ, আমরা কিছু প্রাথমিক ডেটা আনতে চাই, এবং তারপরে প্রাসঙ্গিক অবস্থার পরিবর্তন হলে ডেটা পুনরায় আনতে চাই৷
আমরা immediate: true
বিকল্পটি পাস করে অবিলম্বে একজন পর্যবেক্ষকের কলব্যাক কার্যকর করতে বাধ্য করতে পারি:
js
watch(
source,
(newValue, oldValue) => {
// executed immediately, then again when `source` changes
},
{ immediate: true }
)
watchEffect()
পর্যবেক্ষক কলব্যাকের জন্য উত্স হিসাবে ঠিক একই প্রতিক্রিয়াশীল অবস্থা ব্যবহার করা সাধারণ। উদাহরণ স্বরূপ, নিম্নলিখিত কোডটি বিবেচনা করুন, যেটি রিমোট রিসোর্স লোড করার জন্য একটি প্রহরী ব্যবহার করে যখনই todoId
রেফ পরিবর্তন হয়:
js
const todoId = ref(1)
const data = ref(null)
watch(
todoId,
async () => {
const response = await fetch(
`https://jsonplaceholder.typicode.com/todos/${todoId.value}`
)
data.value = await response.json()
},
{ immediate: true }
)
বিশেষ করে, লক্ষ্য করুন কিভাবে পর্যবেক্ষক দুইবার todoId
ব্যবহার করে, একবার উৎস হিসেবে এবং তারপর আবার কলব্যাকের ভিতরে।
এটি watchEffect()
দিয়ে সরলীকৃত করা যেতে পারে। watchEffect()
আমাদের কলব্যাকের প্রতিক্রিয়াশীল নির্ভরতা স্বয়ংক্রিয়ভাবে ট্র্যাক করতে দেয়। উপরের প্রহরীটিকে এইভাবে পুনরায় লেখা যেতে পারে:
js
watchEffect(async () => {
const response = await fetch(
`https://jsonplaceholder.typicode.com/todos/${todoId.value}`
)
data.value = await response.json()
})
এখানে, কলব্যাক অবিলম্বে চালানো হবে, immediate: true
নির্দিষ্ট করার প্রয়োজন নেই। এটি কার্যকর করার সময়, এটি স্বয়ংক্রিয়ভাবে নির্ভরতা হিসাবে todoId.value
ট্র্যাক করবে (গণনা করা বৈশিষ্ট্যের মতো)। যখনই todoId.value
পরিবর্তিত হয়, কলব্যাক আবার চালানো হবে। watchEffect()
এর সাথে, আমাদের আর todoId
সুস্পষ্টভাবে উৎস মান হিসেবে পাস করতে হবে না।
আপনি watchEffect()
-এর এই উদাহরণ এবং প্রতিক্রিয়াশীল ডেটা-ফেচিং অ্যাকশনে দেখতে পারেন।
এই ধরনের উদাহরণের জন্য, শুধুমাত্র একটি নির্ভরতার সাথে, watchEffect()
এর সুবিধা তুলনামূলকভাবে ছোট। কিন্তু পর্যবেক্ষকদের জন্য যাদের একাধিক নির্ভরতা রয়েছে, watchEffect()
ব্যবহার করে নির্ভরতার তালিকা ম্যানুয়ালি বজায় রাখার বোঝা সরিয়ে দেয়। উপরন্তু, যদি আপনি একটি নেস্টেড ডেটা স্ট্রাকচারে বেশ কয়েকটি বৈশিষ্ট্য দেখতে চান, তাহলে watchEffect()
একটি গভীর পর্যবেক্ষণকারীর চেয়ে বেশি কার্যকরী প্রমাণিত হতে পারে, কারণ এটি কেবলমাত্র কলব্যাকে ব্যবহৃত বৈশিষ্ট্যগুলিকে ট্র্যাক করবে, পুনরাবৃত্তিমূলকভাবে সমস্ত ট্র্যাক করার পরিবর্তে তাদের
TIP
watchEffect
শুধুমাত্র তার synchronous সম্পাদনের সময় নির্ভরতা ট্র্যাক করে। একটি async কলব্যাকের সাথে এটি ব্যবহার করার সময়, প্রথম await
টিক টিক করার আগে শুধুমাত্র অ্যাক্সেস করা বৈশিষ্ট্যগুলি ট্র্যাক করা হবে৷
watch
vs. watchEffect
watch
এবং watchEffect
উভয়ই আমাদের প্রতিক্রিয়াশীলভাবে পার্শ্বপ্রতিক্রিয়া সম্পাদন করতে দেয়। তাদের প্রধান পার্থক্য হল যেভাবে তারা তাদের প্রতিক্রিয়াশীল নির্ভরতা ট্র্যাক করে:
watch
শুধুমাত্র স্পষ্টভাবে দেখা উৎস ট্র্যাক করে। এটি কলব্যাকের ভিতরে অ্যাক্সেস করা কিছু ট্র্যাক করবে না। উপরন্তু, কলব্যাক শুধুমাত্র তখনই ট্রিগার হয় যখন উৎস আসলে পরিবর্তিত হয়।watch
নির্ভরতা ট্র্যাকিংকে পার্শ্বপ্রতিক্রিয়া থেকে আলাদা করে, কলব্যাক কখন চালু হবে তার উপর আমাদের আরও সুনির্দিষ্ট নিয়ন্ত্রণ দেয়।watchEffect
, অন্যদিকে, নির্ভরতা ট্র্যাকিং এবং পার্শ্ব প্রতিক্রিয়াকে এক পর্যায়ে একত্রিত করে। এটি স্বয়ংক্রিয়ভাবে তার সিঙ্ক্রোনাস সম্পাদনের সময় অ্যাক্সেস করা প্রতিটি প্রতিক্রিয়াশীল কম্পিউটেড প্রপার্টি ট্র্যাক করে। এটি আরও সুবিধাজনক এবং সাধারণত টারসার কোডে পরিণত হয়, তবে এর প্রতিক্রিয়াশীল নির্ভরতা কম স্পষ্ট করে তোলে।
Callback Flush Timing
আপনি যখন প্রতিক্রিয়াশীল অবস্থা পরিবর্তন করেন, তখন এটি আপনার দ্বারা তৈরি Vue কম্পোনেন্ট আপডেট এবং প্রহরী কলব্যাক উভয়ই ট্রিগার করতে পারে।
ডিফল্টরূপে, ব্যবহারকারীর তৈরি প্রহরী কলব্যাকগুলিকে আগে Vue কম্পোনেন্ট আপডেট বলা হয়। এর অর্থ হল আপনি যদি একজন প্রহরী কলব্যাকের ভিতরে DOM অ্যাক্সেস করার চেষ্টা করেন, Vue কোনো আপডেট প্রয়োগ করার আগে DOM-টি থাকবে।
আপনি যদি ভিউ এটি আপডেট করার পর একটি প্রহরী কলব্যাকে DOM অ্যাক্সেস করতে চান তবে আপনাকে flush: 'post'
বিকল্পটি নির্দিষ্ট করতে হবে:
js
watch(source, callback, {
flush: 'post'
})
watchEffect(callback, {
flush: 'post'
})
পোস্ট-ফ্লাশ watchEffect()
এরও একটি সুবিধার উপনাম আছে, watchPostEffect()
:
js
import { watchPostEffect } from 'vue'
watchPostEffect(() => {
/* executed after Vue updates */
})
Stopping a Watcher
setup()
বা <script setup>
এর ভিতরে সিঙ্ক্রোনাসভাবে ঘোষিত প্রহরীরা মালিকের কম্পোনেন্ট ইনস্ট্যান্সের সাথে আবদ্ধ থাকে এবং মালিকের কম্পোনেন্ট আনমাউন্ট করা হলে স্বয়ংক্রিয়ভাবে বন্ধ হয়ে যাবে। বেশিরভাগ ক্ষেত্রে, আপনাকে প্রহরীকে থামানোর বিষয়ে চিন্তা করার দরকার নেই।
এখানে মূল বিষয় হল প্রহরীকে synchronously তৈরি করতে হবে: যদি প্রহরী একটি অ্যাসিঙ্ক কলব্যাকে তৈরি করা হয়, তবে এটি মালিকের কম্পোনেন্টের সাথে আবদ্ধ হবে না এবং মেমরি লিক এড়াতে ম্যানুয়ালি বন্ধ করতে হবে। এখানে একটি উদাহরণ:
vue
<script setup>
import { watchEffect } from 'vue'
// this one will be automatically stopped
watchEffect(() => {})
// ...this one will not!
setTimeout(() => {
watchEffect(() => {})
}, 100)
</script>
একজন প্রহরীকে ম্যানুয়ালি থামাতে, রিটার্ন করা হ্যান্ডেল ফাংশনটি ব্যবহার করুন। এটি watch
এবং watchEffect
উভয়ের জন্যই কাজ করে:
js
const unwatch = watchEffect(() => {})
// ...later, when no longer needed
unwatch()
মনে রাখবেন যে খুব কম ক্ষেত্রেই আপনাকে অ্যাসিঙ্ক্রোনাসভাবে পর্যবেক্ষক তৈরি করতে হবে এবং যখনই সম্ভব সিঙ্ক্রোনাস তৈরিকে অগ্রাধিকার দেওয়া উচিত। আপনার যদি কিছু অ্যাসিঙ্ক ডেটার জন্য অপেক্ষা করতে হয়, তাহলে আপনি পরিবর্তে আপনার ওয়াচর যুক্তি শর্তসাপেক্ষ করতে পারেন:
js
// data to be loaded asynchronously
const data = ref(null)
watchEffect(() => {
if (data.value) {
// do something when data is loaded
}
})