SYS.ONLINE
[ ASK_ME ↗ ]
INDEX / DOC // SPEC
660 words
•
3 minutes

Scroll Problem in React Router

Scroll Problem in React Router

ازاي تتحكم في الـscroll لما تنتقل بين الصفحات في React Router 🚀#

المشكلة 🤔#

لو بتستخدم React Router، أكيد قابلتك المشكلة دي قبل كده: لما بتنتقل من صفحة لصفحة، الـscroll مش بيرجع لفوق تلقائي. يعني لو كنت في نص الصفحة وضغطت على لينك يوديك لصفحة تانية، الصفحة الجديدة هتفتح في نفس المكان - مش من فوق.

ليه المشكلة دي بتحصل؟ 🧐#

علشان نفهم المشكلة كويس، لازم نعرف شوية حاجات عن React Router والـSingle Page Applications (SPA)

  1. React Router بيتعامل مع التطبيق كـSPA، يعني صفحة واحدة بتتغير محتواها
  2. مفيش refresh للصفحة لما بننتقل بين الـroutes
  3. React Router مش بيغير الـscroll position تلقائي، علشان
    • ممكن تكون عايز ترجع لنفس المكان لما تدخل على الصفحة تاني
    • ده السلوك الافتراضي في الـSPA

الحلول المتاحة 💡#

الحل الأول: استخدام ScrollRestoration من React Router 📜#

ده أبسط حل وأسرع طريقة. كل اللي عليك تعمله إنك تضيف الـcomponent ده في الـroot component بتاع التطبيق

import { ScrollRestoration } from 'react-router-dom';

function Root() {
  return (
    <>
      <nav>
        {/* قائمة التنقل بتاعتك */}
      </nav>
      
      <Outlet />
      <ScrollRestoration />
    </>
  );
}

الحل التاني: استخدام useLayoutEffect و scrollTo 🔄#

الحل ده مناسب لو عايز:

  • تتحكم أكتر في سلوك الـscroll
  • تمنع أي انيميشن للـscroll
  • تضمن إن الـscroll يحصل قبل ما المستخدم يشوف الصفحة الجديدة
import { useLayoutEffect } from 'react';

function Page() {
  useLayoutEffect(() => {
    window.scrollTo({ top: 0, behavior: 'instant' });
  }, []);

  return (
    <div>
      {/* محتوى الصفحة */}
    </div>
  );
}

ليه useLayoutEffect مش useEffect؟ 🤓#

في فرق مهم بين الاتنين:

  • useEffect بيتنفذ بعد ما React يخلص rendering
  • useLayoutEffect بيتنفذ قبل ما المستخدم يشوف أي تغيير على الشاشة

ده بيمنع حاجة اسمها FOUC (Flash of Unscrolled Content)، يعني المستخدم مش هيشوف الصفحة في المكان القديم قبل ما تتنقل لفوق.

مثال كامل للتطبيق 🌟#

import { createBrowserRouter, RouterProvider, Outlet } from 'react-router-dom';
import { ScrollRestoration } from 'react-router-dom';

// Root Component
function Root() {
  return (
    <>
      <nav>
        <Link to="/">الرئيسية</Link>
        <Link to="/another">صفحة تانية</Link>
      </nav>
      
      <Outlet />
      <ScrollRestoration />
    </>
  );
}

// تعريف الـRoutes
const router = createBrowserRouter([
  {
    path: '/',
    element: <Root />,
    children: [
      {
        path: '/',
        element: <SomePage />
      },
      {
        path: '/another',
        element: <AnotherPage />
      }
    ]
  }
]);

// التطبيق الرئيسي
function App() {
  return <RouterProvider router={router} />;
}

نصائح إضافية 💪#

  1. تأكد إن الـScrollRestoration موجود في أعلى مستوى في التطبيق يعني إيـه؟

أين تضع الـScrollRestoration في تطبيقك؟ 🎯#

المكان الصح ✅#

// App.jsx أو root.jsx
import { createBrowserRouter, RouterProvider, Outlet } from 'react-router-dom';
import { ScrollRestoration } from 'react-router-dom';

function RootLayout() {
  return (
    <div>
      <header>
        <nav>{/* القائمة بتاعتك */}</nav>
      </header>
      
      <ScrollRestoration /> {/* هنا المكان الصح */}
      <Outlet />
      <footer>{/* الفوتر بتاعك */}</footer>
    </div>
  );
}

const router = createBrowserRouter([
  {
    path: '/',
    element: <RootLayout />,
    children: [
      { path: '/', element: <HomePage /> },
      { path: '/about', element: <AboutPage /> }
    ]
  }
]);

export default function App() {
  return <RouterProvider router={router} />;
}

أماكن غلط ❌#

// صفحة فرعية - HomePage.jsx
function HomePage() {
  return (
    <div>
      <ScrollRestoration /> {/* ❌ غلط - مش هيشتغل كويس في كل الحالات */}
      <h1>الصفحة الرئيسية</h1>
    </div>
  );
}

// مكون فرعي - Sidebar.jsx
function Sidebar() {
  return (
    <aside>
      <ScrollRestoration /> {/* ❌ غلط - بعيد عن الـrouting logic */}
      <nav>{/* محتوى السايدبار */}</nav>
    </aside>
  );
}

ليه المكان مهم؟ 🤔#

  1. الـScope:

    • ScrollRestoration لازم يكون في مستوى أعلى من كل الـroutes
    • علشان يقدر يتحكم في الـscroll مع كل تغيير في الـURL
  2. التأثير:

    • لما يكون في المستوى الأعلى، هيأثر على كل الصفحات
    • هيتأكد إن الـscroll بيرجع لفوق مع كل navigation
  3. الـPerformance:

    • وجوده في مكان واحد أفضل من تكراره في كل صفحة
    • بيمنع المشاكل اللي ممكن تحصل من وجود أكتر من instance

أفضل الممارسات 📝#

  1. حط الـScrollRestoration في الـroot layout component
  2. خليه قريب من الـOutlet component
  3. تأكد إنه موجود مرة واحدة بس في التطبيق
  4. متحطوش في components فرعية أو صفحات منفصلة

مثال لهيكل ملفات مثالي 📁#

src/
├── main.jsx          # entry point
├── App.jsx           # فيه RouterProvider
├── layouts/
│   └── RootLayout.jsx  # ✅ حط ScrollRestoration هنا
└── pages/
    ├── HomePage.jsx    # ❌ مش هنا
    └── AboutPage.jsx   # ❌ ولا هنا
  1. لو محتاج تخصص سلوك الـscroll، استخدم الحل التاني
  2. اختبر التطبيق على مختلف المتصفحات علشان تتأكد إن كل حاجة شغالة تمام

الخلاصة ✨#

  • استخدم ScrollRestoration للحل السريع والبسيط
  • استخدم useLayoutEffect لو محتاج تحكم أكتر
  • فكر في تجربة المستخدم واختار الحل المناسب لتطبيقك

Join our whatsapp group here
My Channel here

TERMINAL.COLOPHON // CORE v2.5
LAST.DISPATCH: 2026.09.19
guest@ag-coding:~ (interactive-zsh)
LIVE CLI
RUN //
01 // ISSUES ●
53
Published Articles
02 // CORPUS ≈ 6.7H
80.8K
Total Words Written
03 // SECTORS #
2/39
Categories & Tags
04 // UPTIME 99.9%
ONLINE
Static Edge Node
QUANTUM TELEPORTER // ROULETTE 1-CLICK JUMP
TARGET DESTINATION:
TELEPORT NOW ↗
© 2026 Abdoelaziz Gamal // ALL RIGHTS RESERVED.
30.0444° N, 31.2357° E ■ DESIGNED & ENGINEERED IN CAIRO
OPERATOR // RADAR.HUD
SCROLL.PROGRESS
00% LIVE
Abdoelaziz Gamal
LIVE
// CHIEF ARCHITECT
Abdoelaziz Gamal
REACT.JS NEXT.JS SYS.ARCH
root@ag-coding:~# cat dossier.log ● UTF-8

Full-stack engineer from Mansoura. 5+ years shipping TypeScript / Next.js products — dashboards, multi-tenant apps, CRM, LMS, e-commerce. Behind AG Coding.