רשימות
מבוא
כמעט כל ממשק מציג נתונים בצורת רשימה - מוצרים, הודעות, משתמשים ועוד. ב-React ממירים מערך נתונים לרשימת אלמנטים בעזרת המתודה map(), שיוצרת אלמנט JSX עבור כל פריט במערך:
const fruits = ['תפוח', 'בננה', 'תפוז'];
function FruitList() {
return (
<ul>
{fruits.map(fruit => (
<li key={fruit}>{fruit}</li>
))}
</ul>
);
}
חשיבות ה-key
כל פריט ברשימה חייב key - מזהה ייחודי ויציב שעוזר ל-React לעקוב אחר הפריטים בין רינדורים ולזהות איזה מהם השתנה, נוסף או נמחק. בזכות ה-key, React מעדכנת רק את מה שהשתנה במקום לבנות את כל הרשימה מחדש. המזהה הטבעי ביותר הוא בדרך כלל ה-id שמגיע מהנתונים:
✅ נכון - key ייחודי
const users = [
{ id: 1, name: 'דני' },
{ id: 2, name: 'רונית' },
{ id: 3, name: 'משה' }
];
function UserList() {
return (
<ul>
{users.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
❌ בעייתי - index כ-key
// לא מומלץ! עלול לגרום לבאגים כשהרשימה משתנה
{items.map((item, index) => (
<li key={index}>{item}</li>
))}
כללים ל-key
- חייב להיות ייחודי בין אחים
- חייב להיות יציב - לא להשתנות בין רינדורים
- לא להשתמש ב-
Math.random()אוDate.now() - index מתאים רק לרשימות סטטיות שלא משתנות
רינדור רשימות
רשימה פשוטה
function ColorList() {
const colors = ['אדום', 'ירוק', 'כחול', 'צהוב'];
return (
<ul>
{colors.map((color, index) => (
<li key={index} style={{ color }}>
{color}
</li>
))}
</ul>
);
}
רשימת אובייקטים
function ProductList() {
const products = [
{ id: 1, name: 'מקלדת', price: 150 },
{ id: 2, name: 'עכבר', price: 80 },
{ id: 3, name: 'מסך', price: 1200 }
];
return (
<div className="products">
{products.map(product => (
<div key={product.id} className="product-card">
<h3>{product.name}</h3>
<p>מחיר: ₪{product.price}</p>
</div>
))}
</div>
);
}
רשימה עם קומפוננטה
function ProductCard({ product }) {
return (
<div className="product-card">
<h3>{product.name}</h3>
<p>מחיר: ₪{product.price}</p>
<button>הוסף לסל</button>
</div>
);
}
function ProductList({ products }) {
return (
<div className="products">
{products.map(product => (
<ProductCard key={product.id} product={product} />
))}
</div>
);
}
פעולות על רשימות
סינון (Filter)
function FilteredList() {
const [filter, setFilter] = useState('');
const items = ['תפוח', 'בננה', 'תפוז', 'אבטיח'];
const filteredItems = items.filter(item =>
item.includes(filter)
);
return (
<div>
<input
value={filter}
onChange={(e) => setFilter(e.target.value)}
placeholder="חפש..."
/>
<ul>
{filteredItems.map(item => (
<li key={item}>{item}</li>
))}
</ul>
</div>
);
}
מיון (Sort)
function SortedList() {
const [sortOrder, setSortOrder] = useState('asc');
const items = [
{ id: 1, name: 'ב' },
{ id: 2, name: 'א' },
{ id: 3, name: 'ג' }
];
const sortedItems = [...items].sort((a, b) => {
if (sortOrder === 'asc') {
return a.name.localeCompare(b.name, 'he');
}
return b.name.localeCompare(a.name, 'he');
});
return (
<div>
<button onClick={() => setSortOrder(o => o === 'asc' ? 'desc' : 'asc')}>
מיון: {sortOrder === 'asc' ? '⬆️' : '⬇️'}
</button>
<ul>
{sortedItems.map(item => (
<li key={item.id}>{item.name}</li>
))}
</ul>
</div>
);
}
הוספה ומחיקה
function TodoList() {
const [todos, setTodos] = useState([
{ id: 1, text: 'לקנות חלב' },
{ id: 2, text: 'לשלם חשבונות' }
]);
const [newTodo, setNewTodo] = useState('');
// הוספה
const addTodo = () => {
if (!newTodo.trim()) return;
setTodos(prev => [
...prev,
{ id: Date.now(), text: newTodo }
]);
setNewTodo('');
};
// מחיקה
const deleteTodo = (id) => {
setTodos(prev => prev.filter(todo => todo.id !== id));
};
return (
<div>
<div>
<input
value={newTodo}
onChange={(e) => setNewTodo(e.target.value)}
onKeyPress={(e) => e.key === 'Enter' && addTodo()}
/>
<button onClick={addTodo}>הוסף</button>
</div>
<ul>
{todos.map(todo => (
<li key={todo.id}>
{todo.text}
<button onClick={() => deleteTodo(todo.id)}>❌</button>
</li>
))}
</ul>
</div>
);
}
טבלאות
function UserTable() {
const users = [
{ id: 1, name: 'דני', age: 25, city: 'תל אביב' },
{ id: 2, name: 'רונית', age: 30, city: 'ירושלים' },
{ id: 3, name: 'משה', age: 28, city: 'חיפה' }
];
return (
<table>
<thead>
<tr>
<th>שם</th>
<th>גיל</th>
<th>עיר</th>
</tr>
</thead>
<tbody>
{users.map(user => (
<tr key={user.id}>
<td>{user.name}</td>
<td>{user.age}</td>
<td>{user.city}</td>
</tr>
))}
</tbody>
</table>
);
}
רשימות מקוננות
function CategoryList() {
const categories = [
{
id: 1,
name: 'פירות',
items: ['תפוח', 'בננה', 'תפוז']
},
{
id: 2,
name: 'ירקות',
items: ['מלפפון', 'עגבנייה', 'גזר']
}
];
return (
<div>
{categories.map(category => (
<div key={category.id}>
<h3>{category.name}</h3>
<ul>
{category.items.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
</div>
))}
</div>
);
}
סיכום
| פעולה | מתודה |
|---|---|
| הצגת רשימה | array.map() |
| סינון | array.filter() |
| מיון | [...array].sort() |
| הוספה | [...array, newItem] |
| מחיקה | array.filter(x => x.id !== id) |
| עדכון | array.map(x => x.id === id ? {...x, ...update} : x) |
הקודם: ← רינדור מותנה
הבא: תרגילים →
לחזרה ותרגול חי: הנושא הזה מופיע גם
במדריך האינטראקטיבי ל-React, עם עורך קוד שמראה את התוצאה מיד.
בדקו את עצמכם
נסו לענות לבד לפני שאתם פותחים את התשובה.
-
למה כל איבר ברשימה צריך
key?הצגת התשובה
תשובה ג. key יציב מאפשר עדכון נכון ויעיל.
-
מה עדיף כ-key?
הצגת התשובה
תשובה ד. אינדקס משתנה כשמוחקים או ממיינים, ו-random משתנה בכל רינדור.