جلوگیری از Double Fetch با Route Context در TanStack Router
خلاصهٔ کاملتر
تو پستهای قبلی این سری، TkDodo پیشنهاد کرده بود fetch رو تو route loader شروع کنیم و کامپوننتها با useSuspenseQuery یا useQuery نتیجه رو بگیرن. مشکل اینه که این کار یعنی همون query رو باید تو دو جا تعریف کنی: هم تو loader و هم تو کامپوننت. اگه اپ کوچیک باشه مشکلی نیست، ولی هرچی پروژه بزرگتر میشه نگه داشتن این دوتا هماهنگ سختتر میشه، چون کامپوننتها معمولاً از فایل Route جدا میشن و هیچ خطایی هم نمیگیری اگه از هم واگرا بشن.
بهعنوان مثال، فرض کن یه پارامتر جستجوی اختیاری مثل ?asOf=YYYY-MM-DD به یه صفحهٔ Dashboard اضافه میکنی و فقط تو کامپوننت ازش استفاده میکنی، نه تو loader. نتیجه اینه که وقتی لینک صفحه رو با یکی به اشتراک میذاری، اول loader دیتای امروز رو میگیره، بعد کامپوننت با asOf دوباره fetch میکنه و کاربر یه بار دیگه صبر میکنه تا Query جدید بیاد؛ یعنی دقیقاً همون fetch waterfall ای که قرار بود با loader جلوش گرفته بشه.
راهحل اولیه اینه که loaderDeps رو اضافه کنی تا loader هم از پارامتر باخبر بشه، ولی این فقط علامت رو درمان میکنه نه ریشهٔ مشکل رو، چون هنوز query تو دو جای جدا تعریف شده. راهحل واقعی TkDodo اینه که queryOptions مشترک رو یهبار، تو تابع context روت بسازی و زیر یه کلید تو Route Context بذاری؛ بعد هم loader و هم کامپوننت با Route.useRouteContext() همون یه نسخه رو میخونن، نه اینکه هرکدوم جدا تعریفش کنن.
یه فایدهی جانبی این روش اینه که چون context از روتهای والد به فرزند ارث میرسه، میشه مثلاً دیتای کاربر رو تو روت ریشه prefetch کرد و تو هر زیرروتی بدون تعریف دوباره ازش استفاده کرد. نگرانی بعدی این بود که چون تابع context هر بار یه آبجکت جدید با توابع داخلش میسازه، شاید باعث ریرندر اضافه بشه؛ ولی TkDodo توضیح میده این تابع فقط وقتی params یا loaderDeps عوض بشه اجرا میشه، پس تغییر یه سرچپارامتر بیربط باعث ریرندر کامپوننتهای وابسته به Route Context نمیشه.
نکات کلیدی:
- تعریف جدای query تو route loader و کامپوننت، با گذشت زمان از هم واگرا میشه و هیچ خطایی هم نشون نمیده
- واگرایی باعث دو مشکل میشه: fetch اضافهٔ دادهی بیاستفاده، یا fetch waterfall برای دادهای که لازمه
- راهحل TanStack Router: تعریف queryOptions مشترک تو تابع context روت و خوندنش هم تو loader هم تو کامپوننت با Route.useRouteContext()
- context از روتهای والد به فرزند ارث میرسه، پس میشه دیتای مشترک رو تو روت ریشه یهبار prefetch کرد
- تابع context فقط با تغییر params یا loaderDeps دوباره اجرا میشه، نه با هر تغییر سرچپارامتر، پس ریرندر اضافهای در کار نیست




