6.10 פרויקטים פרויקט
פרויקטים - ריאקט בסיסי¶
הפרויקטים הבאים משלבים את כל מה שלמדנו בפרק הזה: קומפוננטות, props, סטייט, אירועים, רינדור מותנה, רשימות, טפסים, ו-useEffect. כל פרויקט צריך להיבנות עם טייפסקריפט, בגישת "חשיבה בריאקט" - פירוק לקומפוננטות, סטייט מינימלי, ו-composition.
פרויקט 1 - אפליקציית משימות - Todo App¶
בנו אפליקציית משימות מלאה עם CRUD, סינון, ושמירה מקומית.
דרישות פונקציונליות¶
- הוספת משימה חדשה עם טקסט ועדיפות (low/medium/high)
- סימון משימה כהושלמה (toggle)
- עריכת טקסט של משימה קיימת (inline editing)
- מחיקת משימה
- סינון: הכל / פעילות / הושלמו
- סינון לפי עדיפות
- מיון: לפי תאריך יצירה / לפי עדיפות
- חיפוש חופשי בטקסט המשימות
- מונה: X פעילות מתוך Y
- כפתור "נקה הושלמו" שמוחק את כל המשימות שהושלמו
- שמירה ב-localStorage - המשימות נשמרות ונטענות בין רענונים
מבנה קומפוננטות¶
דרישות טכניות¶
- כל קומפוננטה בקובץ נפרד עם interfaces מפורשים ל-props
- טיפוסים מוגדרים בקובץ
types.ts - שמירה ב-localStorage עם useEffect
- טעינה מ-localStorage עם lazy initializer ב-useState
- כל משימה עם id ייחודי (השתמשו ב-
Date.now()או מונה) - עדיפויות מוצגות בצבעים שונים
טיפוסים¶
interface Todo {
id: number;
text: string;
done: boolean;
priority: "low" | "medium" | "high";
createdAt: string;
}
type Filter = "all" | "active" | "completed";
type PriorityFilter = "all" | "low" | "medium" | "high";
type SortBy = "date" | "priority";
נקודות לתשומת לב¶
- הפרידו בין סטייט מקומי (input של הטופס) לסטייט משותף (רשימת המשימות)
filteredTodosהוא ערך מחושב, לא סטייט- inline editing: כשלוחצים "ערוך", ה-TodoItem הופך ל-input. כשלוחצים "שמור" או Enter, חוזר לטקסט
- השתמשו בעדכון פונקציונלי (
prev => ...) כשמעדכנים מערך
פרויקט 2 - אפליקציית מזג אוויר - Weather App¶
בנו אפליקציית מזג אוויר שמאפשרת לחפש מזג אוויר לפי עיר ולשמור ערים מועדפות.
דרישות פונקציונליות¶
- שדה חיפוש עיר עם כפתור חיפוש
- הצגת מזג אוויר: טמפרטורה, תיאור, לחות, רוח, אייקון
- מצבי טעינה ושגיאה
- כפתור "הוסף למועדפים" שמוסיף את העיר לרשימה
- רשימת ערים מועדפות - לחיצה על עיר טוענת את מזג האוויר שלה
- מחיקת עיר מהמועדפים
- מתג צלסיוס/פרנהייט
- שמירת המועדפים וההעדפות ב-localStorage
מבנה קומפוננטות¶
WeatherApp
SearchBar
WeatherCard
WeatherDetails
TemperatureToggle
FavoritesList
FavoriteItem
ErrorMessage
LoadingSpinner
דרישות טכניות¶
- שליפת נתונים עם useEffect ו-fetch
- שימוש ב-API חינמי למזג אוויר (wttr.in format JSON:
https://wttr.in/{city}?format=j1או OpenWeatherMap) - AbortController לביטול בקשות
- ניהול שלושה מצבים: loading, error, success
- שמירה ב-localStorage: רשימת מועדפים + העדפת יחידות
טיפוסים¶
interface WeatherData {
city: string;
temperature: number;
description: string;
humidity: number;
windSpeed: number;
icon: string;
}
type TemperatureUnit = "celsius" | "fahrenheit";
type FetchStatus = "idle" | "loading" | "success" | "error";
interface AppState {
weather: WeatherData | null;
status: FetchStatus;
error: string | null;
favorites: string[];
unit: TemperatureUnit;
}
נקודות לתשומת לב¶
- הפרידו את קריאת ה-API לפונקציה נפרדת
- טפלו ב-AbortController ב-cleanup של useEffect
- המרת טמפרטורה היא חישוב, לא סטייט - שמרו את הטמפרטורה בצלסיוס והמירו בזמן הצגה
- ודאו שהחיפוש מטפל בעיר לא קיימת
פרויקט 3 - אפליקציית חידון - Quiz App¶
בנו אפליקציית חידון אינטראקטיבית עם ניקוד, טיימר, ומעקב אחר תשובות.
דרישות פונקציונליות¶
- מסך פתיחה: שם המשתתף ובחירת קטגוריה (או "הכל")
- שאלות מוצגות אחת אחרי השנייה
- כל שאלה: טקסט השאלה ו-4 אפשרויות תשובה
- חיווי מיידי אם התשובה נכונה או שגויה (ירוק/אדום)
- אי אפשר לשנות תשובה אחרי בחירה
- טיימר של 15 שניות לכל שאלה - אם נגמר הזמן, עוברים לשאלה הבאה עם תשובה שגויה
- כפתור "הבא" שמופיע אחרי בחירת תשובה
- סרגל התקדמות (שאלה 3 מתוך 10)
- מסך סיכום: ציון, מספר תשובות נכונות, זמן ממוצע לתשובה
- אפשרות לראות את כל השאלות עם התשובות (מה בחרת ומה נכון)
- כפתור "התחל מחדש"
- שמירת שיא אישי ב-localStorage
מבנה קומפוננטות¶
QuizApp
StartScreen
QuizScreen
ProgressBar
Timer
QuestionCard
AnswerOption
NextButton
ResultScreen
ScoreSummary
AnswerReview
דרישות טכניות¶
- שאלות מוגדרות במערך (hardcoded, לפחות 15 שאלות ב-3 קטגוריות)
- useEffect לטיימר עם cleanup של setInterval
- סטייט לניהול מצב המשחק: start, playing, finished
- ערבוב שאלות וסדר תשובות בכל משחק חדש
- שמירת היסטוריית תשובות לצורך מסך הסיכום
טיפוסים¶
interface Question {
id: number;
text: string;
options: string[];
correctIndex: number;
category: string;
}
interface Answer {
questionId: number;
selectedIndex: number | null;
isCorrect: boolean;
timeSpent: number;
}
type GameState = "start" | "playing" | "finished";
interface QuizState {
playerName: string;
gameState: GameState;
questions: Question[];
currentIndex: number;
answers: Answer[];
timeLeft: number;
}
נקודות לתשומת לב¶
- הטיימר צריך cleanup כשהקומפוננטה נמחקת או כשעוברים לשאלה הבאה
- סטייט המשחק (
GameState) קובע מה מוצג - שימוש ב-conditional rendering - ערבוב מערך:
[...array].sort(() => Math.random() - 0.5) - זמן ממוצע הוא חישוב מהתשובות, לא סטייט
currentQuestionמחושב מ-questions[currentIndex], לא סטייט נפרד
הנחיות כלליות¶
- כתבו את כל הקוד בטייפסקריפט עם טיפוסים מפורשים
- לכל קומפוננטה קובץ נפרד
- טיפוסים משותפים בקובץ
types.ts - עקבו אחרי עקרונות "חשיבה בריאקט": פירוק, סטייט מינימלי, composition
- טפלו במקרי קצה: רשימה ריקה, שגיאות, טעינה
- השתמשו ב-CSS פשוט (inline styles מספיק, או קובץ CSS אחד)