OOZOU
تواصلوا معنا
العودة إلى المدونة

بناء مواقع ثابتة دون React، باستخدام React (الجزء 2/3)

إدارة ملفات Javascript وملفات الأنماط (stylesheets) وغيرها من الملفات في خط البناء مهمة صعبة. فنحن أمام أسئلة مثل: كيف نتخلص من بيئة تشغيل React داخل الـ bundle؟ وكيف نحسّن ملفات CSS؟ وكيف نتعامل مع الملفات الثابتة؟

22 يوليو 2020
4 دقائق للقراءة
بناء مواقع ثابتة دون React، باستخدام React (الجزء 2/3)

هذا المقال تكملة للجزء الأول من سلسلة "بناء مواقع ثابتة دون React، باستخدام React"، لذا احرصوا على قراءة الجزء الأول قبل المتابعة.

لنتحدث عن التعامل مع ملفات Javascript. إذا استخدمنا "import" التقليدية داخل ملفات المكوّنات، فسينتهي بنا الأمر إلى تجميع كل هذه الملفات في bundle واحد (وهذا جيد) مع بيئة تشغيل React (وهذا جيد أيضًا، لكننا لا نريده في هذه الحالة). ولا يوفر Webpack حاليًا طريقة سهلة لتحديد أي جزء من الـ script يجب تضمينه في الـ bundle. لذلك علينا أن نتجنب صراحةً استيراد الوحدات بشكل ثابت، وأن نلجأ إلى الاستيراد الديناميكي (Dynamic Import).

التطوير أولًا

لا يمكننا استيراد الـ scripts المطلوبة ديناميكيًا في أي مكان داخل ملف المكوّن. علينا أن نفكر بمبدأ "التطوير أولًا" ونحن نرسم طريقنا. فكّروا في الوقت الذي نطوّر فيه الصفحات: يجب ألا تبدأ الـ scripts المضمّنة في كل مكوّن بالتنفيذ إلا بعد عرض المكوّن. فمثلًا، إذا أردنا عنوانًا يتغيّر لونه في إحدى الصفحات، فيجب أن يكون العنوان نفسه موجودًا قبل أن يبدأ script تغيير اللون. كيف نحقق ذلك؟ الجواب في الـ HOOK (نعم، التلاعب بالكلمات مقصود)، والـ hook الذي نستخدمه هو useEffect. بعبارة أخرى، نحن في الواقع ننشئ custom hook يغلّف الـ hook المسمّى useEffect، ونسمّيه "useScripts".

// src/useScripts.js
import { useEffect } from "react";

export function useScripts(scriptLoaders) {
  useEffect(() => {
    loadScripts(scriptLoaders);
  });
}

// Each dynamic import is asynchronous
async function loadScripts(scriptLoaders) {
  for (const load of scriptLoaders) {
    await load();
  }
}

التطوير باستخدام Storybook

سنستخدم في هذا المشروع Storybook للتطوير. لنجهّزه (قد يستغرق ذلك بعض الوقت).

npx -p @storybook/cli sb init

لنحذف ملفات stories المولّدة تلقائيًا، وننشئ stories لصفحتي Home وAboutUs.

// stories/pages.stories.js
import React from "react";

import Home from "../pages/Home";
import AboutUs from "../pages/AboutUs";

export default { title: "Pages" };

export { Home, AboutUs };

الآن يُفترض أن يبدو هيكل المشروع هكذا

├── pages
│   ├── AboutUs.jsx
│   └── Home.jsx
├── scripts
│   └── build.js
├── src
│   └── useScripts.js
├── stories
│   └── pages.stories.js
├── babel.config.js
├── package.json
└── webpack.config.js

الآن شغّلوا

yarn storybook

ثم ننتقل إلى localhost:6006 لننشئ الـ scripts، وهي: src/home.js وsrc/about-us.js

// home.js
console.log("home.js");

const title = document.getElementById("home");

let cyan = true;

title.style.transition = "color 0.5s";

setInterval(() => {
  title.style.color = cyan ? "cyan" : "black";
  cyan = !cyan;
}, 1000);
//about-us.js
console.log("about-us.js");

والآن لنستوردهما عبر useScripts.

//Home.jsx
import React from "react";
import { useScripts } from "../src/useScripts";

const Home = () => {
  useScripts([() => import("../src/home")]);
  return <h1 id="home">Home Page</h1>;
};

export default Home;
import React from "react";
import { useScripts } from "../src/useScripts";

const AboutUs = () => {
  useScripts([() => import("../src/about-us")]);
  return <h1>About Us</h1>;
};

export default AboutUs;

كما ترون، نتوقع بعد الدخول إلى صفحة Home أن يُنفَّذ home.js ويغيّر لون العنوان كل ثانية. وها هو يعمل!

ملفات الأنماط (Stylesheets)

ذكرت أن عبارات import العادية تجلب معها بيئة تشغيل React، لكن استيراد ملفات الأنماط والملفات الثابتة لا يفعل ذلك، لذا يمكننا استيرادها بالطريقة المعتادة. لننشئ الملف pages/Home.css ونعدّل الملفات المرتبطة به.

// Home.css
#home {
  transition: color 0.2s;
}
// Home.jsx
import React from "react";
import { useScripts } from "../src/useScripts";

import "./Home.css"; // import stylesheets

const Home = () => {
  useScripts([() => import("../src/home")]);
  return <h1 id="home">Home Page</h1>;
};

export default Home;

ويمكننا أيضًا حذف سطر الـ transition المكتوب بأسلوب أمري (imperative) في home.js

// home.js
console.log("home.js");

const title = document.getElementById("home");

let cyan = true;

// title.style.transition = "color 0.5s"; <-- remove this

setInterval(() => {
  title.style.color = cyan ? "cyan" : "black";
  cyan = !cyan;
}, 1000);

وهذا كل ما يتعلق بالتطوير تقريبًا. سنتوقف هنا الآن. لم نتحدث بعد عن عملية البناء التي تنتج ملفات HTML وJS وCSS النهائية، فتابعونا في الجزء التالي!

Related Articles

كيف أصمّم برمجيات؟ دليل المبتدئين لأصحاب الأعمال

كيف أصمّم برمجيات؟ دليل المبتدئين لأصحاب الأعمال

تصميم البرمجيات عملية ممتعة لكنها معقدة، تتطلب الإبداع والتفكير المنطقي ومهارات حل المشكلات.

اقرأوا المزيد
مستقبل الحوسبة الطرفية: ما تحتاج الشركات إلى معرفته

مستقبل الحوسبة الطرفية: ما تحتاج الشركات إلى معرفته

يتطور المشهد الرقمي بسرعة، وعلى الشركات أن تتكيّف لتواكب الطلب المتزايد على السرعة والكفاءة والمعالجة في الوقت الفعلي.

اقرأوا المزيد
مستقبل قطاع التجزئة: الذكاء الاصطناعي والواقع المعزّز واتجاهات التحوّل الرقمي

مستقبل قطاع التجزئة: الذكاء الاصطناعي والواقع المعزّز واتجاهات التحوّل الرقمي

يتطور قطاع التجزئة بوتيرة غير مسبوقة بفضل الذكاء الاصطناعي (AI) والواقع المعزّز (AR) وتقنيات التحوّل الرقمي. فلم تعد المتاجر التقليدية مجرد أماكن لبيع المنتجات، بل أصبحت متاجر ذكية وتفاعلية.

اقرأوا المزيد

Have a Project in Mind?

Let's discuss how we can help bring your ideas to life with our expertise in web and mobile development.

ابدأوا المحادثةhello@oozou.com
OOZOU Logo

بانكوك · سنغافورة · هونغ كونغ

X
Facebook
Instagram
LinkedIn
OOZOU Co., Ltd.
548 One City Centre
Ploenchit Road
Bangkok 10330
Thailand
+66 2544 0000
hello@oozou.com

الخدمات

  • تطوير الويب
  • وكلاء الذكاء الاصطناعي والذكاء الاصطناعي التوليدي
  • تطوير تطبيقات الجوال
  • تحليلات البيانات وهندستها
  • تصميم تجربة المستخدم وواجهته (UX/UI) وتصميم المنتجات
  • التحوّل الرقمي

الشركة

  • من نحن
  • الوظائف
  • المدونة
  • دراسات الحالة
  • عروض حية
  • تعلّمت اليوم
  • تواصل معنا

المزيد

  • القطاعات
  • شبكة الشركاء
© 2026 OOZOU. جميع الحقوق محفوظة.
سياسة الخصوصيةمدونة قواعد السلوكسياسة مكافحة الرشوة والفساد