Gratulacje, astronauto! Dotarłeś do finałowej misji w module React Mastery. Czas połączyć wszystkie poznane technologie w jeden, potężny system — Kosmiczne Centrum Dowodzenia Misją. Ten projekt to twój ostateczny test, który sprawdzi, czy opanowałeś zaawansowane wzorce React.
Zbudujesz dashboard do zarządzania kosmiczną misją, który łączy kluczowe koncepty z całego modułu:
Użyj React Portals do renderowania modalnych okien alertów misji poza głównym drzewem DOM. Alerty powinny pojawiać się nad interfejsem z efektem overlay.
Dodaj przełącznik języka (PL/EN) do nagłówka. Cały dashboard powinien zmieniać język interfejsu dynamicznie za pomocą Context API i obiektów z tłumaczeniami.
Zarządzaj stanem misji (status, paliwo, załoga, systemy) za pomocą
useReducer. Zdefiniuj akcje takie jak LAUNCH_MISSION, UPDATE_FUEL, TOGGLE_SYSTEM, ADD_CREW_MEMBER.Stwórz komponent
<Dashboard.Panel> w wzorcu Compound Components, który pozwala elastycznie komponować sekcje dashboardu:1<Dashboard>
2 <Dashboard.Header title="Mission Control" />
3 <Dashboard.Panel title="Systems">
4 <SystemsList />
5 </Dashboard.Panel>
6 <Dashboard.Panel title="Crew">
7 <CrewList />
8 </Dashboard.Panel>
9</Dashboard>Opakuj sekcje dashboardu w Error Boundaries, aby awaria jednego panelu nie powodowała crashu całej aplikacji. Wyświetl przyjazny komunikat błędu z opcją ponownego załadowania sekcji.
Zastosuj
React.memo na komponentach listy, useMemo na obliczeniach statystyk misji i useCallback na handlerach zdarzeń przekazywanych do komponentów potomnych.1App
2├── LanguageProvider (Context — i18n)
3├── MissionProvider (useReducer — state)
4├── Dashboard (Compound Component)
5│ ├── Dashboard.Header
6│ ├── Dashboard.Panel "Status Misji"
7│ │ └── ErrorBoundary
8│ │ └── MissionStatus (React.memo)
9│ ├── Dashboard.Panel "Systemy"
10│ │ └── ErrorBoundary
11│ │ └── SystemsList (React.memo)
12│ └── Dashboard.Panel "Załoga"
13│ └── ErrorBoundary
14│ └── CrewList (React.memo)
15└── Portal → AlertModal (React Portal)1const initialState = {
2 status: 'preparing',
3 fuel: 100,
4 systems: [
5 { id: 1, name: 'Navigation', active: true },
6 { id: 2, name: 'Life Support', active: true },
7 { id: 3, name: 'Communications', active: false },
8 ],
9 crew: ['Kowalski', 'Nowak', 'Wiśniewska'],
10};
11
12function missionReducer(state, action) {
13 switch (action.type) {
14 case 'LAUNCH_MISSION':
15 return { ...state, status: 'in-flight', fuel: state.fuel - 20 };
16 case 'UPDATE_FUEL':
17 return { ...state, fuel: Math.max(0, state.fuel + action.payload) };
18 case 'TOGGLE_SYSTEM':
19 return {
20 ...state,
21 systems: state.systems.map(s =>
22 s.id === action.payload ? { ...s, active: !s.active } : s
23 ),
24 };
25 case 'ADD_CREW_MEMBER':
26 return { ...state, crew: [...state.crew, action.payload] };
27 default:
28 return state;
29 }
30}1const translations = {
2 pl: { launch: 'Rozpocznij misję', fuel: 'Paliwo', systems: 'Systemy' },
3 en: { launch: 'Launch Mission', fuel: 'Fuel', systems: 'Systems' },
4};
5
6const LanguageContext = createContext();
7
8function LanguageProvider({ children }) {
9 const [lang, setLang] = useState('pl');
10 const t = translations[lang];
11 return (
12 <LanguageContext.Provider value={{ lang, setLang, t }}>
13 {children}
14 </LanguageContext.Provider>
15 );
16}1function AlertModal({ message, onClose }) {
2 return createPortal(
3 <div className="modal-overlay">
4 <div className="modal-content">
5 <h2>Alert!</h2>
6 <p>{message}</p>
7 <button onClick={onClose}>Zamknij</button>
8 </div>
9 </div>,
10 document.getElementById('modal-root')
11 );
12}Wykorzystaj poniższy edytor kodu jako punkt startowy. Rozbuduj aplikację o brakujące funkcjonalności i dopasuj ją do struktury opisanej powyżej.