دروس8 دقايق ديال القراية

أول مشروع React بالدارجة: من JavaScript لسلّة مشتريات

أول مشروع React خطوة بخطوة: سلّة فيها كميات، مجموع وبحث. JSX وcomponents وprops وmap وkey وuseState، مع الكود كامل فـ GitHub.

كاين حتى ب : Français

Mehdi بلباس الأستاذ، غلاف المقال: أول مشروع React

أحسن طريقة تبدا بيها React هي تبني واجهة صغيرة كاملة، ماشي أمثلة مقطعة. فدرس E27، كنبنيو البوتيك ديال Hamza: بطاقات ديال المنتوجات، سلة مشتركة فيها الكميات، مجموع كيتحسب بوحدو، وبحث. وفالطريق، كنشوفو JSX و components و props و map و key، ومن بعد useState و les événements.

علاش ندوزو من JavaScript لـ React؟

الدرس كيبدا بتجربة مقصودة بـ JavaScript « vanilla »: Bob كيكليكي على « Casque »، العدد كيولي 1… والمجموع باقي 0 درهم. علاش؟ بدلنا العدد فـ DOM، ونسينا نبدلو المجموع. JavaScript يقدر يديرها بلا مشكل؛ المشكل هو أنه فكل تغيير، خاصك تتفكر كلشي اللي خاصو يتبدل فالشاشة.

الفكرة ديال React: كنبدلو المعلومات، كنوصفو شنو خاصو يبان، و React كيتكلف بالتغييرات فالواجهة.

كيفاش نجيب المشروع؟

الكود ديال البداية والحل public:

sh
git clone https://github.com/Laraibi/lara-academy-react-fundamentals.git
cd lara-academy-react-fundamentals
npm ci
npm run dev

حل l'adresse اللي كيعطيك Vite (عادة http://127.0.0.1:5173). والحل ديال الدرس فالـ branch solution.

شنو هو JSX؟

App هو component: فونكسيون كترجع وصف ديال الواجهة. وهاد الكتابة اللي كتشبه لـ HTML سميتها JSX. بين الأقواس { } كنحطو تعبير ديال JavaScript، بحال {product.price}. بدل الثمن من 150 لـ 160، سجل، والصفحة كتتبع. وجوج تفاصيل: فـ JSX كنكتبو className بلاصة class، و main.jsx هو اللي كيربط App بالبلاصة ديالو فالصفحة.

Components و props: نعاودو نستعملو نفس البطاقة

بلاصة ما نعاودو نكتبو البطاقة ديال الكاسك للكلافيي، كنجمعوها فـ component سميتو ProductCard، كيستقبل المعلومات ديالو بـ props، بحال المعلومات اللي كتعطي لفونكسيون:

jsx
export default function ProductCard({ product, onAdd }) {
  return (
    <article>
      <h2>{product.name}</h2>
      <p>{product.price} DH</p>
      <button onClick={() => onAdd(product)}>Ajouter {product.name}</button>
    </article>
  );
}

(حيدنا les classes ديال Tailwind باش يكون الكود واضح.) الأقواس اللي فالبارامتر كتخرج product من الأوبجي اللي وصل. نفس الكود، ومعلومات مختلفة. والقاعدة: props كنقراوهم كيف ما وصلو؛ وإلا بغينا تغيير، كنطلبوه من المكون المسؤول عليه.

كيفاش نعرضو لائحة بـ map و key؟

إلا كانو عندك عشرين منتوج، ما غاديش تكتب عشرين بطاقة. كنجمعو المنتوجات فطابلو، ونستعملو map، اللي كتعطينا طابلو جديد فيه بطاقة لكل منتوج:

js
export const PRODUCTS = [
  { id: 'casque', name: 'Casque', price: 150 },
  { id: 'clavier', name: 'Clavier', price: 200 },
  { id: 'souris', name: 'Souris', price: 80 },
];
jsx
{visibleProducts.map(product => (
  <ProductCard key={product.id} product={product} onAdd={handleAdd} />
))}

key كتخلي React يميز العناصر ديال اللائحة. كنستعملو id ثابت لكل منتوج: ماشي رقم عشوائي، وماشي رقم البلاصة إلا اللائحة كتبدل.

علاش let count ما كتبدلش الشاشة؟

تجربة بوحدها: زر كيحسب الكليكات بـ let count = 0. كتكليكي، الكونسول كيبين 1، والشاشة باقية 0. الفونكسيون خدمات، ولكن تبديل variable عادية ما كيطلبش من React يعاود يحسب الواجهة. وزيد، هاد الـ variable كترجع لصفر فكل مرة كيتنفذ المكون.

useState و les événements

useState كترد جوج حوايج: القيمة، وفونكسيون باش نطلبو تبديلها.

jsx
import { useState } from 'react';

export default function Counter() {
  const [count, setCount] = useState(0);

  function handleClick() {
    setCount(previous => previous + 1);
    console.log('Valeur dans ce rendu :', count);
  }

  return <button onClick={handleClick}>Clics : {count}</button>;
}

شنو كيورينا الدرس:

  • onClick كتاخد فونكسيون؛ ما كنعيطوش ليها وسط العرض.
  • من بعد setCount، React كيعاود يعيط للمكون، كيحسب شنو خاص يبان، وكيبدل فـ DOM غير داكشي اللي تبدل.
  • مباشرة من بعد setCount، count باقية بالقيمة ديال هاد العرض: القيمة الجديدة كتبان فالعرض الجاي (وهادا علاش درنا console.log).
  • useState كنعيطو ليها فوق فالمكون، ماشي داخل شرط ولا داخل فونكسيون الكليك.

فين نحطو السلة المشتركة؟

إلا كل بطاقة عندها state ديالها، كل وحدة كتحسب بوحدها. والبطاقات كتطلب الإضافة، والسلة كتعرض النتيجة: الـ parent اللي جامعهم هو App. تما كنحطو state ديال السلة، كندوزو المعلومات لتحت بـ props، وكنعطيو للبطاقة فونكسيون onAdd. و onAdd ماشي حدث ديال React: هادي prop سميناها حنا.

jsx
const [cart, setCart] = useState([]);

function handleAdd(product) {
  setCart(previous => addItem(previous, product));
}

function handleRemove(id) {
  setCart(previous => removeOne(previous, id));
}

كيفاش نزيدو منتوج بلا ما نبدلو الطابلو؟

ما كنديروش push فالطابلو اللي فـ state: كنصاوبو واحد جديد.

js
export function addItem(cart, product) {
  const exists = cart.some(item => item.id === product.id);
  if (exists) {
    return cart.map(item => item.id === product.id
      ? { ...item, quantity: item.quantity + 1 }
      : item);
  }
  return [...cart, { ...product, quantity: 1 }];
}
  • some كتجاوبنا: واش كاين شي عنصر عندو نفس id؟
  • إلا كان، map كترجع كل عنصر كيف ما هو، غير هو كتصاوبو من جديد بكمية زايدة بواحد.
  • وإلا ما كانش، النقط الثلاثة ... كتخرج العناصر اللي كانو، وكنزيدو المنتوج بكمية 1.

التجربة فالدرس: جوج مرات Casque، ومرة Souris → 3 وحدات، 2 سطور، 380 درهم.

نحيدو وحدة ونحسبو المجموع

js
export function removeOne(cart, id) {
  return cart
    .map(item => item.id === id
      ? { ...item, quantity: item.quantity - 1 }
      : item)
    .filter(item => item.quantity > 0);
}

export function getTotal(cart) {
  return cart.reduce((sum, item) => sum + item.price * item.quantity, 0);
}

كننقصو الكمية بواحد، ومن بعد filter كتخلي غير العناصر اللي باقي عندها أكثر من صفر. والدرس كينصح: كتب التوقع ديالك قبل ما تجرب. ملي كنحيدو وحدة بوحدة، المجموع كيدوز من 380 لـ 230، ومن بعد 80، ومن بعد 0.

والمجموع ما محتاجش state بوحدو: كيتحسب من السلة فكل عرض. و reduce كتبدا من 0، إذن السلة الخاوية كتعطي 0.

بحث ما كيخويش السلة

المعلومة الجديدة اللي خاصنا نحتافظو بيها هي داكشي اللي كتبتي، ماشي اللائحة اللي خرجات:

jsx
const [query, setQuery] = useState('');
const visibleProducts = PRODUCTS.filter(product =>
  product.name.toLowerCase().includes(query.trim().toLowerCase())
);

<input type="search" value={query} onChange={event => setQuery(event.target.value)} />

value كتقرا state، و onChange كتطلب تبديلها: هادا champ contrôlé. إلا ما لقينا والو، كتبان « Aucun produit trouvé. »، والكاسك اللي زدتي باقي فالسلة، حيت البحث كيبدل غير شنو كيبان فالكاتالوغ. وما احتاجينا حتى useEffect، لا للائحة لا للمجموع.

أسئلة كيتعاودو

شنو خاصني نعرف قبل أول مشروع React؟

شوية ديال HTML و CSS، والفونكسيونات والطابلوات فـ JavaScript. و map و filter كنعاودو نشرحوهم فالبلاصة اللي كنحتاجوهم فيها.

شنو الفرق بين props و state؟

props معلومات كتوصل للمكون؛ و state معلومة كيحتافظ بيها، ونقدرو نطلبو تبديلها بالفونكسيون اللي كترد useState.

واش خاص useEffect باش نحسبو المجموع ولا نفيلتريو اللائحة؟

لا. المجموع واللائحة المفيلترية كيتحسبو فالعرض، من السلة ومن كلمة البحث. المشروع ما فيه حتى useEffect.

علاش السلة كتمشي ملي كنعاود نحمل الصفحة؟

المشروع ما فيه لا stockage لا API: state كتبقى فالميموار. الربط مع API جا فالحلقة اللي من بعد.

شنو خاصك تحفظ

  • props: معلومات كتوصل للمكون. state: معلومة كيحتافظ بيها، ونقدرو نطلبو تبديلها.
  • حط state فالـ parent اللي جامع المكونات اللي محتاجينها.
  • عمرك تبدل طابلو ديال state مباشرة: صاوب واحد جديد (...، map، filter).
  • اللي كيتحسب (المجموع، اللائحة المفيلترية) ما كيمشيش لـ state.
  • key ثابتة لكل عنصر فاللائحة.

شوف الدرس

الدرس كامل (13 دقيقة و34 ثانية، بالدارجة) فالصفحة ديالو: من JavaScript إلى React: أول سلّة مشتريات (E27).

  • 00:00 علاش المجموع ما تبعش الكليك؟
  • 00:49 المشروع و starter ديال React + Tailwind
  • 01:49 JSX: المعلومات وسط الواجهة
  • 03:35 Components و props
  • 04:33 نعرضو لائحة بـ map و key
  • 05:23 علاش let count ما كتبدلش الشاشة
  • 06:08 useState و les événements
  • 07:15 نحطو السلة فالـ parent
  • 08:26 نزيدو منتوج بلا ما نبدلو الطابلو
  • 09:40 نحيدو وحدة ونحسبو المجموع
  • 10:50 البحث والخدمة الجماعية بـ Git
  • 12:42 Récap والتحدي

زيد قدام

المصادر

Quiz: 3 أسئلة باش تتأكد

حتى حاجة ما كتصيفط: الأجوبة ديالك كيبقاو ف المتصفح ديالك.

  1. كليكيتي، والكونسول بين count ولات 1، ولكن الشاشة باقي فيها 0. علاش؟
  2. علاش ما نديروش cart.push(product) ومن بعد setCart(cart)؟
  3. واش المجموع ديال السلة خاصو state بوحدو؟

بارطاجي

تكتب من الدرس والنص ديالو بمساعدة أدوات الذكاء الاصطناعي، وراجعو وتأكد منو Mehdi Laraibi نهار 4 نونبر 2026.