جاوااسکریپت - NextJs <Link> اسکریپتها را دوباره اجرا نمیکند


وقتی از تگ <Link> در NextJs برای حرکت بین صفحات استفاده میکنم، اسکریپتهایم بعد از تغییر صفحات دوباره اجرا نمیشوند. این اسکریپتها فقط بعد از اولین بارگذاری صفحه یا وقتی که دکمه بازخوانی را میزنم اجرا میشوند. وقتی به جای آن از تگهای معمولی <a> استفاده میکنم، کار میکند چون صفحه بعد از هر حرکت تازه میشود. تا جایی که فهمیدهام این اتفاق میافتد چون تگ <Link> باعث میشود برنامه یکصفحهای (SPA) باشد و هنگام حرکت بین صفحات، صفحه تازه نشود.

من بسیار قدردان خواهم بود اگر راهی وجود داشته باشد که اسکریپتها هنگام جابجایی بین صفحات دوباره اجرا شوند یا صفحه بدون استفاده از تنها تگهای <a> تازه شود و عملکرد برنامه تکصفحهای از دست نرود.

این کد صفحه را تازه نمیکند

 <Link href="/page1">
   <a>Page 1</a>
 </Link>
 <Link href="/page2">
   <a>Page 2 </a>
 </Link>

این کد صفحه را تازه میکند

 <a href="/page1">Page 1</a>
 <a href="/page2">Page 2 </a>

من تمام اسکریپتهایم را با استفاده از یک کامپوننت اسکریپت بارگذاری میکنم

export default const MyScripts = () => {
    
    return (
        <Script
            strategy="afterInteractive"
            type="module"
            src="/scripts/myScript.js"
            onReady={() => {
                console.log("Ready")
            }}
        /> 
    )
}

یک چیزی که متوجه شدهام این است که تابع onReady بالا هر بار که صفحهها را تغییر میدهم اجرا میشود. شاید کسی بداند چگونه میتوان myScript.js را از onReady اجرا کرد.

پاسخ شماره ۱

من از این برای حل آن استفاده میکردم. این هر بار که URL تغییر میکند، آنچه میخواهید دوباره اجرا شود را دوباره اجرا میکند.

function name(history){
    var pushState = history.pushState;
    history.pushState = function(state) {
       // YOUR CUSTOM HOOK / FUNCTION
       console.log('I am called from pushStateHook');
       return pushState.apply(history, arguments);
    };
})
name(history)

پیادهسازی من در myScript.js

function myFunctions(){
    //my code
}

function urlChange(history){
    let pushState = history.pushState;
    history.pushState = function(state) {
        myFunctions();//I insert my code here
        return pushState.apply(history, arguments);
    };
}
urlChange(history);

همچنین من کاملاً مطمئنم که history.pushState=function(state){} چیزی است که هر بار که آدرس URL تغییر میکند اجرا میشود، نه تابع urlChange().

پاسخ شماره ۲

احتیاط: استفاده از هک history.pushState به طور قابل اطمینان کار نخواهد کرد، به ویژه زمانی که عناصر DOM باید با استفاده از document.querySelector* گرفته شوند. به هر حال، بهتر است اگر میتوانید از هکها اجتناب کنید.

روش توصیهشده برای Next.js استفاده از مؤلفه Script همراه با اسکریپت درونخطی است.

به سادگی کد جاوااسکریپت خود را از تگ script به یک کامپوننت Script منتقل کنید. تگ HTML script و هر فایل اسکریپت را حذف کنید زیرا دیگر نیازی به آنها ندارید.

import Script from 'next/script';

// Inside your exported component:
<Script id="myScript">
  // Paste the contents of /scripts/myScript.js here (and remove that file)
</Script>

یک روش تمیز دیگر برای انجام این کار استفاده از هوک useEffect در ریاکت است. در کامپوننتهای مبتنی بر کلاس، میتوانید از componentDidMount استفاده کنید.

این ایده در اینجا پیشنهاد شد: نظر samplep182 در: اسکریپتهای عادی "" بعد از مرور صفحه کار نمیکنند - مسئله #4477 - vercel/next.js

به سادگی کد Javascript خود را از تگ script به یک بلوک useEffect منتقل کنید. تگ script و هر فایل اسکریپت را حذف کنید زیرا دیگر به آنها نیاز ندارید.

import { useEffect } from 'react';

// Inside your exported component:
useEffect(() => {
  // Paste the contents of /scripts/myScript.js here (and remove that file)
}, []);

یادداشتها:

  1. توصیه میشود که یک آرایه خالی [] به عنوان فهرست وابستگی داشته باشید، تا این تنها هنگام بارگذاری صفحه اجرا شود.

  2. برای اسکریپتهای خارجی، لطفاً از المان Script با ویژگی src استفاده کنید.