499 words
2 minutes
Key Prop in React

المشكلة#

مستحيل تكون اشتغلت بريأكت ومشوفتش الـ Warning ده:

Warning: Each child in a list should have a unique "key" prop

وأكيد في اللحظة دي فكرت “ما هو مجرد warning”، بس صدقني يا صديقي، الموضوع أخطر من كده بكتير. الـ warning ده ممكن يكون سبب لمشاكل كبيرة في الـ application بتاعك.

إيه هو الـ Key Prop أصلاً؟ 🔑#

الـ key prop ده زي البطاقة الشخصية بتاعت كل عنصر في الـ DOM. لازم يكون:

  • Unique (مفيش اتنين عناصر ليهم نفس الـ key)
  • Static (ثابت ومبيتغيرش)

ليه لازم نهتم بالـ Keys? 🎯#

لو استخدمت الـ key غلط أو مستخدمتوش أصلاً، هتواجه مشاكل زي:

  • Performance issues
  • UI bugs
  • Data inconsistency
  • State management problems

الغلطة الشائعة: استخدام Index كـ Key ❌#

// مثال للكود الغلط
todos.map((todo, index) => (
  <TodoItem key={index} {...todo} />
))

ليه استخدام الـ Index مش كويس؟#

  1. مينفعش تستخدم index في الحالات دي:
    • لما تضيف items في أول أو نص الـ array
    • لما تعمل filter للـ array
    • لما الـ list بتاعك dynamic

مثال من الحياة العملية 🌍#

تخيل إنك شغال على تطبيق Todo List:

السيناريو الأول (باستخدام index كـ key):#

const todos = [
  { text: "Task 1" }, // key: 0
  { text: "Task 2" }, // key: 1
  { text: "Task 3" }  // key: 2
];

لما نضيف task جديدة في الأول:#

const todos = [
  { text: "Task 4" }, // key: 0 😱
  { text: "Task 1" }, // key: 1 
  { text: "Task 2" }, // key: 2
  { text: "Task 3" }  // key: 3
];

المشكلة الكبيرة 💥#

  • لو المستخدم كان بيعدل في Task 3
  • وضاف task جديدة في الأول
  • كل الـ keys هتتغير
  • والتعديلات ممكن تضيع أو تتنقل لـ task تانية!

الحل الصح ✅#

1. استخدام ID من الـ Backend#

todos.map(todo => (
  <TodoItem key={todo.id} {...todo} />
))

1. استخدام crypto.randomUUID() اللي بتكون Built-in في المتصفحات الحديثة#

function generateId() {
  return crypto.randomUUID();
}

// مثال للاستخدام
function TodoList() {
  const [todos, setTodos] = useState(() => [
    { id: generateId(), text: 'Task 1' },
    { id: generateId(), text: 'Task 2' }
  ]);

  const addTodo = (text) => {
    setTodos(prev => [...prev, { 
      id: generateId(), 
      text 
    }]);
  };

  return (
    <ul>
      {todos.map(todo => (
        <TodoItem key={todo.id} {...todo} />
      ))}
    </ul>
  );
}

3. استخدام UUID Package#

import { v4 as uuidv4 } from 'uuid';

const todos = [
  { id: uuidv4(), text: "Task 1" },
  { id: uuidv4(), text: "Task 2" },
  { id: uuidv4(), text: "Task 3" }
];

نصائح مهمة 🚨#

  1. متستخدمش Math.random() كـ key (ممكن يطلع نفس الرقم مرتين)
  2. خلي الـ key generation يحصل قبل الـ component mounting يعني إوعي تعمل كدا
function TodoList() {
  const [todos, setTodos] = useState([]);

  return (
    <ul>
      {todos.map(todo => {
        // غلط: توليد الـ key في كل render
        const randomKey = Math.random();
        return <TodoItem key={randomKey} todo={todo} />
      })}
    </ul>
  );
}
  1. في حالة الـ static lists اللي مش بتتغير، ممكن تستخدم index كـ key

الحالات اللي ممكن فيها تستخدم Index كـ Key 🤔#

  1. لما تكون الـ list ثابتة مش بتتغير
  2. لما الـ items الجديدة بتتضاف في آخر الـ array بس
  3. لما مفيش filtering بيحصل على الـ list

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

  1. استخدم IDs من الـ backend
  2. استخدم UUID في حالة عدم وجود IDs
  3. اعمل generation للـ keys قبل الـ render
  4. تأكد إن الـ key ثابت ومش بيتغير مع الوقت

Join our whatsapp group here
My Channel here