مهارات JavaScript التي تحتاجها لتعلّم React مع أمثلة عملية

دقائق القراءة: 9

إذا كنت ترغب في إتقان React، فهناك حقيقة أساسية يجب أن تضعها في المقدمة: React ليست بديلاً عن JavaScript، بل هي مبنية عليها بالكامل. لذلك، كلما كانت معرفتك بـ JavaScript أقوى، أصبح تعاملك مع React أسرع وأكثر احترافية.

في هذا الدليل، نستعرض أهم 7 مهارات أساسية في JavaScript يحتاجها كل مطور React، مع أمثلة عملية تساعدك على فهم سبب أهميتها في المشاريع الواقعية.

أهم مهارات جافاسكربت المطلوبة لتعلّم رياكت مع أمثلة عملية للمطورين

1. فهم الدوال في JavaScript وكتابة مكوّنات React

اللبنة الأساسية في React هي المكوّن Component. وغالباً ما يتم تعريف هذا المكوّن باستخدام دوال JavaScript. الفرق الجوهري أن الدالة العادية قد تعيد أي قيمة صحيحة في اللغة، بينما مكوّن React يعيد عناصر JSX لبناء الواجهة.

// JavaScript function: returns any valid JavaScript type
function javascriptFunction() {
  return "Hello world";
}

// React function component: returns JSX
function ReactComponent(props) {
  return <h1>{props.content}</h1>;
}

من المهم أيضاً ملاحظة أسلوب التسمية:

  • الدوال العادية غالباً تُكتب بصيغة camelCase.
  • مكوّنات React تُكتب بصيغة PascalCase.

الفرق بين Function Declaration وArrow Function

يمكنك كتابة الدوال بطريقتين شائعتين:

  1. الدالة التقليدية باستخدام الكلمة المفتاحية function.
  2. الدالة السهمية باستخدام الصياغة =>.
// Function declaration syntax
function MyComponent(props) {
  return <div>{props.content}</div>;
}

// Arrow function syntax
const MyComponent = (props) => {
  return <div>{props.content}</div>;
};

// Arrow function shorthand
const MyComponent = (props) => <div>{props.content}</div>;

تُفضَّل الدوال السهمية غالباً لأنها مختصرة وأكثر أناقة، خاصة عند كتابة مكوّنات بسيطة. كما تسمح لك ببعض الاختصارات مثل:

  • حذف الأقواس عند وجود معامل واحد فقط.
  • استخدام الإرجاع الضمني Implicit Return.
  • حذف الأقواس المعقوفة عند اختصار جسم الدالة.

متى تكون الدالة التقليدية أفضل؟

إحدى مزايا Function Declaration أنها تستفيد من خاصية hoisting، أي يمكن استدعاؤها قبل تعريفها داخل الملف. أما المكوّنات المكتوبة بصيغة Arrow Function فيجب تعريفها قبل استخدامها.

function App() {
  return (
    <>
      {/* Valid! FunctionDeclaration is hoisted */}
      <FunctionDeclaration />

      {/* Invalid! ArrowFunction is NOT hoisted */}
      <ArrowFunction />
    </>
  );
}

function FunctionDeclaration() {
  return <div>Hello React!</div>;
}

const ArrowFunction = function () {
  return <div>Hello React, again!</div>;
};

ومن الفروقات العملية أيضاً أن التصدير المباشر باستخدام export default يكون أكثر سلاسة مع الدالة التقليدية:

// Function declaration with immediate export
export default function App() {
  return <div>Hello React</div>;
}

// Arrow function with named export
export const App = () => {
  return <div>Hello React</div>;
};

2. استخدام Template Literals لبناء النصوص الديناميكية

قبل ظهور ES6، كان دمج النصوص في JavaScript يتم غالباً عبر المعامل +، وهو أسلوب يعمل، لكنه يصبح مربكاً مع النصوص الطويلة أو القيم المتغيرة.

function sayHello(text) {
  return "Hello " + text + "!";
}

sayHello("React");

أما مع Template Literals، فيمكنك استخدام العلامتين ` ` وحقن أي تعبير داخل الصيغة ${} بشكل أوضح بكثير:

function sayHelloAgain(text) {
  return `Hello again, ${text}!`;
}

sayHelloAgain("React");

تكمن قوة هذا الأسلوب في أنه لا يقتصر على المتغيرات فقط، بل يدعم أي تعبير صالح في JavaScript، بما في ذلك الشروط.

import React from "react";

function App() {
  const [isRedColor, setRedColor] = React.useState(false);
  const toggleColor = () => setRedColor((prev) => !prev);

  return (
    <button
      onClick={toggleColor}
      style={{
        background: isRedColor ? "red" : "black",
        color: "white",
      }}
    >
      Button is {isRedColor ? "red" : "not red"}
    </button>
  );
}

هذا النمط مفيد جداً داخل React عند إنشاء عناوين الصفحات، وأسماء الأصناف className، ورسائل الواجهة المتغيرة.

import React from "react";
import Head from "./Head";

function Layout(props) {
  const title = `${props.title} | Reed Barger`;

  return (
    <>
      <Head>
        <title>{title}</title>
      </Head>
      <main>{props.children}</main>
    </>
  );
}

3. الشروط المختصرة داخل React: && و|| وTernary

إظهار العناصر أو إخفاؤها شرطياً من أكثر الأنماط استخداماً في React. وبما أن JSX يعتمد على JavaScript، يمكنك استخدام الشروط التقليدية مثل if، أو اللجوء إلى صيغ مختصرة أكثر ملاءمة داخل الواجهة.

import React from "react";

function App() {
  const isLoggedIn = true;

  if (isLoggedIn) {
    return <div>Welcome back!</div>;
  }

  return <div>Who are you?</div>;
}

export default App;

المعامل الثلاثي Ternary Operator

هذا المعامل مثالي عندما تحتاج إلى الاختيار بين قيمتين أو عنصرين:

import React from "react";

function App() {
  const isLoggedIn = true;

  return isLoggedIn
    ? <div>Welcome back!</div>
    : <div>Who are you?</div>;
}

export default App;

كما يمكن استخدامه داخل JSX مباشرة:

import React from "react";

function App() {
  const isLoggedIn = true;

  return <div>{isLoggedIn ? "Welcome back!" : "Who are you?"}</div>;
}

export default App;

المعامل && للإظهار المشروط

إذا كنت تريد عرض شيء فقط عند تحقق الشرط، فالمعامل && هو الخيار الأنسب:

import React from "react";

function App() {
  const isLoggedIn = true;

  return <div>{isLoggedIn && "Welcome back!"}</div>;
}

export default App;

المعامل || كقيمة بديلة

يمكن استخدام || لإرجاع قيمة بديلة عندما تكون القيمة الأولى غير محققة:

import React from "react";

function App() {
  const isLoggedIn = false;

  return <div>{isLoggedIn || "Who are you?"}</div>;
}

export default App;

لكن عملياً، يجب استخدام هذا النمط بحذر داخل JSX حتى لا ينتج سلوكاً غير متوقع مع القيم غير المنطقية مثل الأرقام أو السلاسل الفارغة.

4. أهم دوال المصفوفات: .map() و.filter() و.reduce()

في تطبيقات React، من الشائع جداً التعامل مع بيانات تأتي على شكل مصفوفات، مثل قوائم المستخدمين أو المنتجات أو التعليقات. لذلك، يجب أن تتقن دوال المصفوفات الحديثة.

import React from "react";

function App() {
  const name = "Reed";
  const bio = {
    age: 28,
    isEnglishSpeaker: true,
  };

  return (
    <>
      <h1>{name}</h1>
      <h2>I am {bio.age} years old</h2>
      <p>Speaks English: {String(bio.isEnglishSpeaker)}</p>
    </>
  );
}

export default App;

استخدام .map() لعرض القوائم

الدالة .map() تُستخدم لتحويل كل عنصر داخل المصفوفة إلى عنصر جديد. وفي React تُستخدم عادة لتحويل البيانات إلى عناصر JSX.

import React from "react";

function App() {
  const programmers = ["Reed", "John", "Jane"];

  return (
    <ul>
      {programmers.map((programmer) => (
        <li key={programmer}>{programmer}</li>
      ))}
    </ul>
  );
}

export default App;

من الأفضل دائماً إضافة الخاصية key عند إنشاء القوائم في React لتسهيل تتبع العناصر أثناء إعادة التصيير.

استخدام .filter() لتصفية البيانات

إذا كنت تريد عرض جزء من البيانات فقط، فإن .filter() تتيح لك استبعاد العناصر غير المطلوبة قبل عرضها:

import React from "react";

function App() {
  const programmers = ["Reed", "John", "Jane"];

  return (
    <ul>
      {programmers
        .filter((programmer) => !programmer.startsWith("J"))
        .map((programmer) => (
          <li key={programmer}>{programmer}</li>
        ))}
    </ul>
  );
}

export default App;

استخدام .reduce() لفهم التحويلات المتقدمة

الدالة .reduce() أكثر مرونة من .map() و.filter()، لأنها تتيح لك تحويل المصفوفة إلى أي نوع من البيانات، وليس فقط إلى مصفوفة جديدة.

import React from "react";

function App() {
  const programmers = ["Reed", "John", "Jane"];

  return (
    <ul>
      {programmers
        .reduce((acc, programmer) => {
          if (!programmer.startsWith("J")) {
            return acc.concat(programmer);
          }
          return acc;
        }, [])
        .map((programmer) => (
          <li key={programmer}>{programmer}</li>
        ))}
    </ul>
  );
}

export default App;

إتقان .reduce() يمنحك فهماً أعمق لكيفية معالجة البيانات في الواجهات المعقدة، لكنه ليس دائماً الخيار الأبسط. استخدمه عندما تحتاج إليه فعلاً، لا لمجرد استعراض المهارة.

5. حيل الكائنات في JavaScript: الاختصار والتفكيك والنشر

الكائنات Objects جزء أساسي من العمل مع React، سواء في props أو الحالة state أو البيانات القادمة من واجهات API.

اختصار خصائص الكائن Property Shorthand

إذا كان اسم المتغير هو نفسه اسم الخاصية، يمكنك كتابة الاسم مرة واحدة فقط:

const name = "Reed";

const user = {
  name,
};

console.log(user.name);

تفكيك الكائنات باستخدام Destructuring

بدلاً من الوصول إلى كل خاصية عبر اسم الكائن في كل مرة، يمكنك استخراج القيم مباشرة في متغيرات مستقلة:

const user = {
  name: "Reed",
  age: 28,
  isEnglishSpeaker: true,
};

const name = user.name;
const age = user.age;

const { age: userAge, name: userName, isEnglishSpeaker: knowsEnglish } = user;

console.log(knowsEnglish);

هذا الأسلوب مفيد جداً داخل مكوّنات React، خصوصاً عند التعامل مع props:

function Profile({ name, age }) {
  return <p>{name} is {age} years old</p>;
}

عامل النشر Spread Operator

عند إنشاء كائن جديد بناءً على كائن موجود، يوفّر عامل النشر ... طريقة مختصرة وواضحة:

const user = {
  name: "Reed",
  age: 28,
  isEnglishSpeaker: true,
};

const secondUser = {
  ...user,
};

كما يمكنك دمج أكثر من كائن في كائن واحد:

const user = {
  name: "Reed",
  age: 28,
};

const moreUserInfo = {
  age: 70,
  country: "USA",
};

const secondUser = {
  ...user,
  ...moreUserInfo,
  computer: "MacBook Pro",
};

console.log(secondUser);

لاحظ أن الخصائص المتأخرة بالاسم نفسه تستبدل القيم السابقة، ولذلك يجب الانتباه لترتيب الدمج.

6. التعامل مع Promises وAsync/Await في تطبيقات React

معظم تطبيقات React الحديثة تتعامل مع عمليات غير متزامنة Asynchronous، مثل جلب البيانات من API أو إرسالها إلى الخادم. وهنا يظهر دور Promises.

استخدام .then() و.catch()

الصيغة التقليدية للتعامل مع Promise تعتمد على ردود النداء callbacks عبر .then() و.catch():

import React from "react";

const App = () => {
  const [avatar, setAvatar] = React.useState("");

  React.useEffect(() => {
    fetch("https://api.github.com/users/reedbarger")
      .then((response) => response.json())
      .then((data) => setAvatar(data.avatar_url))
      .catch((error) => console.error("Error fetching data:", error));
  }, []);

  return <img src={avatar} alt="Reed Barger" />;
};

export default App;

لماذا يفضّل كثيرون async/await؟

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

import React from "react";

const App = () => {
  const [avatar, setAvatar] = React.useState("");

  React.useEffect(() => {
    async function fetchAvatar() {
      const response = await fetch("https://api.github.com/users/reedbarger");
      const data = await response.json();
      setAvatar(data.avatar_url);
    }

    fetchAvatar();
  }, []);

  return <img src={avatar} alt="Reed Barger" />;
};

export default App;

لاحظ أن الدالة الممررة مباشرة إلى useEffect() لا ينبغي أن تكون async، لذلك ننشئ دالة داخلية ثم نستدعيها.

التعامل مع الأخطاء بشكل صحيح

من الأخطاء الشائعة الاعتقاد أن fetch() يرمي خطأ تلقائياً عند ظهور حالة مثل 404. في الواقع، يجب التحقق من الخاصية response.ok يدوياً.

import React from "react";

const App = () => {
  const [avatar, setAvatar] = React.useState("");

  React.useEffect(() => {
    async function fetchAvatar() {
      try {
        const response = await fetch("https://api.github.com/users/reedbarge");

        if (!response.ok) {
          const message = `An error has occurred: ${response.status}`;
          throw new Error(message);
        }

        const data = await response.json();
        setAvatar(data.avatar_url);
      } catch (error) {
        console.error(error);
      }
    }

    fetchAvatar();
  }, []);

  return <img src={avatar} alt="Reed Barger" />;
};

export default App;

في المشاريع الحقيقية، من الأفضل عرض حالة تحميل ورسالة خطأ واضحة للمستخدم بدلاً من الاكتفاء بطباعة الخطأ في وحدة التحكم console.

7. فهم ES Modules وصيغة import/export

تنظيم الشيفرة إلى ملفات قابلة لإعادة الاستخدام من أساسيات بناء التطبيقات الكبيرة. وتسمح لك ES Modules باستيراد وتصدير الدوال والمتغيرات والملفات الأخرى بسهولة.

import React from "react";
import logo from "../img/site-logo.png";
import "../styles/app.css";

function App() {
  return (
    <div>
      Welcome!
      <img src={logo} alt="Site logo" />
    </div>
  );
}

export default App;

الفرق بين Named Export وDefault Export

يمكنك تصدير عناصر متعددة بالاسم named، بينما يسمح لك التصدير الافتراضي default بتصدير عنصر واحد رئيسي من الملف.

// constants.js
export const name = "Reed";
export const age = 28;

export default function getName() {
  return name;
}

// app.js
import getName, { name, age } from "../constants.js";

console.log(name, age, getName());

كما يمكنك كتابة التصديرات في نهاية الملف:

// constants.js
const name = "Reed";
const age = 28;

function getName() {
  return name;
}

export { name, age };
export default getName;

إعادة التسمية باستخدام as

إذا كنت تريد استيراد اسم مختلف لتجنّب التعارض أو لتوضيح المعنى، استخدم as:

// app.js
import getMyName, { name as myName, age as myAge } from "../constants.js";

console.log(myName, myAge, getMyName());

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

أفضل طريقة لتطوير مستواك في React

إتقان React لا يحدث عبر حفظ المكوّنات أو تكرار الأمثلة فقط، بل من خلال بناء أساس قوي في JavaScript. عندما تفهم الدوال، والشروط، والمصفوفات، والكائنات، والعمليات غير المتزامنة، والوحدات البرمجية، ستجد أن كثيراً من مفاهيم React تصبح أوضح وأسهل بكثير.

دورة تعليمية لتطوير مهارات رياكت وجافاسكربت مع أمثلة عملية للمبتدئين والمحترفين

الخلاصة التقنية

من الناحية التقنية، لا يمكن فصل النجاح في React عن التمكن من JavaScript. أكثر المفاهيم التي تصنع فرقاً حقيقياً في سرعة التطوير وجودة الشيفرة هي: كتابة الدوال بمرونة، استخدام الشروط المختصرة داخل JSX، التعامل الذكي مع المصفوفات والكائنات، وفهم Promises وasync/await وES Modules. إذا أتقنت هذه المهارات جيداً، فلن تتعلم React فقط، بل ستكتب تطبيقات أوضح وأسهل في الصيانة وأكثر جاهزية للتوسع.

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *