جاوااسکریپت | JavaScript
511 subscribers
664 photos
143 videos
3 files
520 links
کانال @IR_javascript حاوی اطلاعات مفید در حوزه برنامه نویس فرانت که بصورت روزانه بروز می‌شود.
در این کانال شما به:
[1] مطالب تازه
[2] تحلیل‌های عمیق
[3] نکات آموزشی
[4] چالش
[5] ابزار و راهنمایی‌های کاربردی
دسترسی خواهید داشت.

🆔@IR_javascript
Download Telegram
در این مطلب می‌خواهیم درباره دو هوک کاربردی در Vue به نام‌های onRenderTracked() و onRenderTriggered() صحبت کنیم — ابزارهایی که معمولاً کمتر مورد استفاده قرار می‌گیرند، در حالی که بسیار مفید هستند!

### این دو چه کاری انجام می‌دهند؟

‏- `onRenderTracked`: نشان می‌دهد که Vue هنگام رندر شدن، چه چیزهایی را دنبال و رصد می‌کند (یعنی چه چیزی را "ردگیری" می‌کند).
‏- `onRenderTriggered`: مشخص می‌کند که چه چیزی تغییر کرده و باعث اجرای مجدد رندر شده است.

### چه زمانی باید از آن‌ها استفاده کرد؟

- زمانی که یک کامپوننت بیش از حد و بدون دلیل واضحی رندر می‌شود.
- وقتی قصد بهینه‌سازی عملکرد (Performance Debugging) را دارید.
- زمانی که مشغول بررسی کدی هستید که توسط فرد دیگری نوشته شده یا خودتان مدتی پیش نوشته‌اید و حالا علت رفتارهای آن را نمی‌دانید.

### نمونه‌ای از استفاده:

<script setup>
import { ref, onRenderTracked, onRenderTriggered } from 'vue';

const count = ref(۰);
const name = ref('Vue');

onRenderTracked((e) => {
console.log('[tracked]', e);
});

onRenderTriggered((e) => {
console.log('[triggered]', e);
});
</script>

<template>
<div>
<p>شمارنده: {{ count }}</p>
<p>نام: {{ name }}</p>
<button @click="count++">افزایش</button>
</div>
</template>


زمانی که روی دکمه کلیک می‌کنید، در کنسول پیغامی مشابه زیر نمایش داده می‌شود:

[triggered] { target: ..., key: "count", type: "set" }


### چه چیزی در این هوک‌ها به شما داده می‌شود؟

Vue یک شیء با فیلدهای زیر به شما تحویل می‌دهد:

‏- effect: ارجاع به افکت واکنشی (یعنی رندر مربوطه)
‏- target: شیئی که تحت نظر قرار گرفته یا باعث اجرای مجدد شده (مانند ref یا reactive)
‏- key: فیلد مشخصی که رصد شده (مثل count یا name)
‏- type: نوع عملیات (مانند get`، `set`، `add`، `delete`، `clear)
‏- oldValue و newValue (در onRenderTriggered) — مقادیر پیش و پس از تغییر

### چه کاربردهای مفیدی دارند؟

#### شناسایی رندرهای غیرضروری
فرض کنید کامپوننت شما هنگام تغییر یک متغیر رندر می‌شود، در حالی که آن متغیر اصلاً در قالب (template) استفاده نشده. در این حالت می‌توانید با استفاده از onRenderTriggered و مشاهده خروجی کنسول، بفهمید که علت رندر چیست. اگر کلید مورد نظر در قالب استفاده نشده باشد، احتمالاً باید کد را بازنگری کنید.

#### لاگ‌گیری وابستگی‌ها
می‌توانید اطلاعات ردیابی‌شده را در قالب جدول چاپ کنید تا راحت‌تر متوجه شوید کامپوننت شما چه چیزهایی را دنبال می‌کند:

onRenderTracked((e) => {
console.table({
key: e.key,
type: e.type,
target: e.target
});
});


#### تحلیل عملکرد
می‌توانید شمارنده‌ای برای تعداد دفعات اجرای onRenderTriggered قرار دهید. اگر با یک کلیک، ده‌ها بار این تابع اجرا شود، احتمال وجود یک مشکل در ساختار کامپوننت وجود دارد.

---

### خلاصه:
‏- onRenderTracked = ببین Vue هنگام رندر چه چیزی را ردیابی می‌کند.
‏- onRenderTriggered = ببین چه چیزی تغییر کرده و باعث رندر مجدد شده.
- این ابزارها برای دیباگ و بهینه‌سازی بسیار کاربردی هستند.
- فقط در حالت توسعه (dev mode) استفاده شوند.



#️⃣#tip #vue
👥@IR_javascript_group
🆔@IR_javascript
👍3
کامپوننت KeepAlive در Vue یک کامپوننت پوششی خاص است که اجازه می‌دهد یک کامپوننت پس از حذف شدن از DOM همچنان در حافظه باقی بماند. به‌عبارت دیگر، Vue آن را از بین نمی‌برد، بلکه به‌آرامی کنار می‌گذارد تا در صورت نیاز دوباره مورد استفاده قرار گیرد. عملکرد آن شبیه به display: none است، با این تفاوت که تمام داده‌ها، واکنش‌پذیری و وضعیت داخلی کامپوننت حفظ می‌شود.

### کاربرد رایج:
فرض کنید در برنامه خود از زبانه‌ها (Tabs) یا مسیرها (Routes) استفاده می‌کنید و می‌خواهید هنگام جابه‌جایی بین زبانه‌ها، اطلاعات واردشده، موقعیت اسکرول و سایر وضعیت‌ها حفظ شوند:

<KeepAlive>
<component :is="currentTabComponent" />
</KeepAlive>


### اگر بخواهم کنترل کنم چه چیزی کش شود، چه کنم؟

از نسخه دو ممیز یک ممیز صفر به بعد، KeepAlive دارای دو پراپرتی include و exclude است که می‌توانید نام کامپوننت‌ها را برای کش شدن یا نشدن، در آن‌ها مشخص کنید.

#### نمونه‌ها:

رشته‌ای از نام‌ها (با ویرگول جدا شده):

<KeepAlive include="a,b">
<component :is="view" />
</KeepAlive>


عبارت منظم (Regex):

<KeepAlive :include="/a|b/">
<component :is="view" />
</KeepAlive>


آرایه‌ای از نام‌ها:

<KeepAlive :include="['a', 'b']">
<component :is="view" />
</KeepAlive>


### همچنین می‌توانید از prop به نام max استفاده کنید تا مشخص کنید حداکثر چند کامپوننت در حافظه نگهداری شود:

<KeepAlive max="۲">
<component :is="currentTabComponent" />
</KeepAlive>


---

### چه چیزهایی در Vue ۳ جدید است؟

در گذشته، یک کامپوننت یا کش می‌شد یا نمی‌شد — همین! اما در Vue ۳، امکانات بیشتری برای کنترل رفتار فراهم شده است.

### رفتار جدید: هوک‌های onActivated و onDeactivated

وقتی یک کامپوننت در KeepAlive قرار می‌گیرد، برخلاف حالت عادی، Vue دیگر unmounted را اجرا نمی‌کند. در عوض، این دو هوک اجرا می‌شوند:

onActivated(() => {
console.log('من دوباره فعال شدم!');
});

onDeactivated(() => {
console.log('وقت استراحته!');
});


این یعنی شما می‌توانید:
- تایمرها را موقتاً متوقف کنید
- از منابع سنگین جدا شوید (unsubscribe)
- انیمیشن‌ها را متوقف کرده یا به حالت تعلیق درآورید

### چه زمانی بهتر است استفاده نشود؟

- زمانی که کامپوننت "ارزان" است و رندر شدن آن زمان زیادی نمی‌برد
- زمانی که حفظ وضعیت کامپوننت برایتان اهمیتی ندارد
- زمانی که می‌خواهید کامپوننت با هر بار نمایش، کاملاً از نو ساخته شود

---

### خلاصه‌ی مطالب:

‏- KeepAlive کامپوننت‌ها را در حافظه نگه می‌دارد
- از onActivated و onDeactivated به‌جای unmounted استفاده می‌کند
- امکان فیلتر کردن کامپوننت‌ها با include و exclude وجود دارد
- می‌توان با max تعداد کامپوننت‌های ذخیره‌شده را محدود کرد
- فقط با یک فرزند (یا تگ <component>) به‌درستی کار می‌کند



#️⃣#tip #vue
👥@IR_javascript_group
🆔@IR_javascript
2
گاهی اوقات هنگام نوشتن یک کامپوننت، انواع ویژگی‌ها مانند id`، `class`، `style و یا ویژگی‌هایی با پیشوند data-* را به آن ارسال می‌کنید، اما این ویژگی‌ها در خروجی نهایی ناپدید می‌شوند. چرا؟ چون Vue به‌صورت پیش‌فرض این ویژگی‌ها را به‌طور خودکار روی تمام المنت‌ها اعمال نمی‌کند. ولی موضوع به همین سادگی هم نیست — ظرافت‌هایی دارد.

### دقیقاً چه اتفاقی می‌افتد؟

Vue تمامی ویژگی‌هایی را که صراحتاً به‌عنوان props تعریف نکرده‌اید**، جمع‌آوری کرده و آن‌ها را روی **المان ریشه‌ای (Root Element) کامپوننت شما قرار می‌دهد.

#### مثال:
<MyButton class="big red" id="super-btn" />


و درون MyButton.vue چنین چیزی نوشته‌اید:

<template>
<button>کلیک کن</button>
</template>


در این صورت، ویژگی‌های class="big red" و id="super-btn" به دکمه اضافه می‌شوند.
ساده و کاربردی، نه؟

---

### اگر از ساختار سفارشی استفاده کرده باشم چه می‌شود؟

اگر نخواهید Vue به‌طور خودکار این ویژگی‌ها را به هر جایی منتقل کند و ترجیح دهید خودتان تعیین کنید این ویژگی‌ها به کدام عنصر بروند**، در این صورت می‌توانید از `v-bind="$attrs"` استفاده کنید.

#### نمونه:

<template>
<div>
<button>دکمه شماره یک</button>
<button v-bind="$attrs">دکمه شماره دو</button>
</div>
</template>



در اینجا فقط دکمه دوم ویژگی‌هایی مثل `id` و `class` را دریافت می‌کند.

---

### اگر اصلاً نخواهید
Vue چیزی منتقل کند چه؟

اگر بخواهید کنترل کامل را در دست داشته باشید، می‌توانید انتقال خودکار ویژگی‌ها را غیرفعال کنید. کافی‌ست گزینه زیر را در کامپوننت‌تان اضافه کنید:


<template>
<div class="wrapper">
<button v-bind="$attrs">دکمه</button>
</div>
</template>

<script setup>
defineOptions({
inheritAttrs: false
})
</script>



در این حالت، **هیچ ویژگی‌ای به عنصر ریشه‌ای (div) اضافه نمی‌شود
و تنها به دکمه منتقل خواهد شد. این کار زمانی بسیار مفید است که بخواهید استایل‌ها یا رویدادها دقیقاً روی یک عنصر تعاملی مثل دکمه اعمال شوند.

---

### نکات مهم:

- هر چیزی که prop نباشد، در $attrs قرار می‌گیرد.
- به‌صورت پیش‌فرض، تمام این ویژگی‌ها به عنصر ریشه‌ای کامپوننت افزوده می‌شوند.
- اگر می‌خواهید کنترل بیشتری داشته باشید، از inheritAttrs: false و v-bind="$attrs" استفاده کنید.
- می‌توان $attrs را هم در بخش setup و هم در template به‌کار برد.
- اگر نام یک ویژگی با نام prop یکی باشد، آن ویژگی دیگر وارد $attrs نمی‌شود.

این ویژگی‌ها به شما کمک می‌کنند کنترل دقیق‌تری بر ساختار، استایل و رفتار کامپوننت‌های خود داشته باشید — خصوصاً در کامپوننت‌های قابل استفاده مجدد و پیچیده.

#️⃣#tip #vue
👥@IR_javascript_group
🆔@IR_javascript
👍2
کتاب Chibi Vue نوشته‌ی یویچی کیکوچی، راهنمایی جامع و دقیق درباره‌ی ساختار درونی فریم‌ورک Vue ۳ است. این کتاب به‌ویژه برای توسعه‌دهندگانی که به‌صورت عمیق در حال یادگیری Vue هستند، بسیار سودمند است.

در این کتاب می‌خوانید:

تحلیل جامع هسته‌ی Vue، شامل: سامانه‌ی واکنش‌پذیری، کامپایلر قالب‌ها، و سیستم رندرینگ.

پیاده‌سازی عملی و گام‌به‌گام نسخه‌ای ساده‌شده از Vue از ابتدا.

زبان این کتاب انگلیسی است.
🔗https://book.chibivue.land/
#️⃣#tip #vue
👥@IR_javascript_group
🆔@IR_javascript
متوقف کردن یک Watcher

Watcher**هایی که به‌صورت هم‌زمان (synchronous) درون تابع `setup()` یا در قالب `<script setup>` تعریف می‌شوند، به نمونه (instance) کامپوننت مالک وابسته هستند و به‌طور خودکار هنگام **unmount شدن آن کامپوننت متوقف خواهند شد. در اغلب موارد، نیازی نیست نگران متوقف کردن دستی آن‌ها باشید.

نکته‌ی کلیدی در این‌جاست که Watcher باید به‌صورت هم‌زمان ایجاد شود؛ اگر Watcher در یک تابع غیرهم‌زمان (asynchronous) مانند setTimeout ایجاد گردد، دیگر به کامپوننت والد وابسته نخواهد بود و باید به‌صورت دستی متوقف شود تا از نشت حافظه (memory leak) جلوگیری شود. به مثال زیر توجه کنید:
<script setup>
import { watchEffect } from 'vue'

// این Watcher به‌صورت خودکار متوقف خواهد شد
watchEffect(() => {})

// ...اما این یکی نه!
setTimeout(() => {
watchEffect(() => {})
}, ۱۰۰)
</script>

برای متوقف کردن دستی یک Watcher**، می‌توان از تابع بازگشتی استفاده کرد. این روش هم برای `watch` و هم برای `watchEffect` کاربرد دارد:


const unwatch = watchEffect(() => {})

// ...در زمانی دیگر، زمانی که دیگر نیازی نیست
unwatch()


توجه داشته باشید که تنها در موارد بسیار محدود نیاز به ایجاد **Watcher
به‌صورت غیرهم‌زمان وجود دارد، و در هر زمان ممکن، بهتر است از ایجاد هم‌زمان استفاده شود.

اگر نیاز دارید منتظر داده‌ای غیرهم‌زمان بمانید، می‌توانید منطق Watcher خود را مشروط طراحی کنید:

// داده‌ای که به‌صورت غیرهم‌زمان بارگذاری می‌شود
const data = ref(null)

watchEffect(() => {
if (data.value) {
// انجام عملیات زمانی که داده بارگذاری شد
}
})


#️⃣#tip #vue
👥@IR_javascript_group
🆔@IR_javascript
1👍1
در هنگام استفاده از router-view همراه با transition و تعیین `mode="out-in"`، در حالت توسعه (dev mode)، هنگام جابه‌جایی بین مسیرها (routes) اغلب با مشکل نمایش صفحه سفید مواجه می‌شویم.

تنها راه‌حل مؤثری که تاکنون یافته شده، غیرفعال کردن این حالت (mode) در زمان توسعه است.

نمونه‌ای از کد مربوطه:

<router-view v-slot="{ Component }">
<Transition mode="out-in">
<component :is="Component" />
</Transition>
</router-view>


در این وضعیت، پیشنهاد می‌شود برای جلوگیری از بروز مشکل، در محیط توسعه از مقدار پیش‌فرض mode یا از حالت‌هایی مانند "in-out" یا بدون مشخص‌کردن mode استفاده شود و تنها در محیط تولید (production) از حالت out-in بهره بگیرید، چرا که این حالت در محیط توسعه ممکن است باگ‌هایی مانند نمایش صفحه سفید موقت ایجاد کند.



#️⃣#tip #vue
👥@IR_javascript_group
🆔@IR_javascript
👍31