پشت پرده یه navigate() ساده توی TanStack Router
خلاصهٔ کاملتر
از دید کد اپلیکیشن، یه navigate() توی TanStack Router خیلی ساده به نظر میرسه، ولی وقتی چند اتفاق روی هم میافتن (مثلاً هاور کردن یه لینک، کلیک کردن یه لینک دیگه قبل از تموم شدن لودینگ، و ریدایرکت شدن یکی از لودرها) همهچی پیچیده میشه. به گفته نویسنده، این پیچیدگی باعث دهها باگ جدا از هم توی preload، ریدایرکت، کش و UI پندینگ شده بود که همهشون یه ریشه مشترک داشتن: روتر خیلی واقعیت رو توی تعداد کمی متغیر جمع کرده بود و لغو، جایگزینی، انتشار و رندر رو با هم قاطی میکرد.
راهحلی که توی PR بازنویسی لودینگ پیاده شده، هر navigation رو به چهار مالک جدا تقسیم میکنه. یه flight یعنی یه لودر در حال اجرا که با شمارش lease (یعنی هر کی بهش نیاز داره یه سهم ازش میگیره) مشخص میشه کِی واقعاً باید لغو بشه؛ برای همین حتی اگه navigation اصلی عوض بشه، لودری که preload شروعش کرده هنوز میتونه ادامه پیدا کنه و نتیجهش کش بشه.
یه current transaction هم فقط یه اسلات داره که مشخص میکنه کدوم navigation اجازه انتشار (publish) صفحه رو داره؛ وقتی navigation بعدی این اسلات رو میگیره، navigation قبلی دیگه نمیتونه صفحه رو آپدیت کنه حتی اگه لودرش هنوز کار میکنه.
یه lane هم نتیجههای همه لودرهای یه مسیر رو جمع میکنه و تصمیم میگیره: اگه یکی از لودرها ریدایرکت بده، حتی اگه لودر دیگهای زودتر خطا داده باشه، ریدایرکت برنده میشه و یه navigation جدید شروع میشه؛ اون خطا هیچوقت به صفحه نمیرسه. در آخر، چون React ممکنه هنوز مشغول رندر کردن درخت قبلی باشه یا درخت جدید سوسپند (suspend) بشه، انتشار به معنی رندر شدن نیست؛ برای همین یه render receipt با مقدار ack:true یا ack:false مشخص میکنه که فریمورک واقعاً اون انتشار رو کامیت کرده یا نه.
برای اینکه یه lane بفهمه دیگه اجازه انتشار نداره، فقط کافیه چک کنه که هنوز صاحب transaction هست یا نه:
if (router._tx !== tx) {
finishPending(tx)
discardLane(result)
return
}نکات کلیدی:
- بازنویسی موتور لودینگ TanStack Router در PR شماره ۷۸۰۵ انجام شده و دهها باگ قدیمی رو حل کرده
- flight با شمارش lease مشخص میکنه یه لودر مشترک (مثلاً preload) کِی واقعاً باید لغو بشه
- current transaction فقط یه navigation رو در هر لحظه مجاز به انتشار صفحه میکنه
- lane نتیجههای چند لودر رو با هم جمع میکنه؛ ریدایرکت همیشه روی خطا اولویت داره
- render receipt با ack:true یا ack:false مشخص میکنه فریمورک واقعاً انتشار رو رندر کرده یا نه




