Wyobraz sobie, ze na Twoim statku kosmicznym zamiast recznego konfigurowania kazdego systemu optymalizacji, masz inteligentny autopilot, ktory automatycznie wykrywa i optymalizuje wszystkie redundantne operacje. Dokladnie to robi React Compiler (znany rowniez jako React Forget) - automatycznie analizuje Twoj kod i dodaje memoizacje tam, gdzie jest potrzebna.
Do tej pory, optymalizacja wydajnosci w React wymagala recznego stosowania
React.memo, useMemo i useCallback. To jak reczne konfigurowanie kazdego systemu na statku kosmicznym - czasochlonne, podatne na bledy i latwe do przeoczenia:1// PRZED React Compiler - reczna memoizacja
2import { useState, useMemo, useCallback, memo } from 'react';
3
4const MissionCard = memo(function MissionCard({ mission, onSelect }) {
5 return (
6 <div onClick={() => onSelect(mission.id)}>
7 <h3>{mission.name}</h3>
8 <p>Status: {mission.status}</p>
9 </div>
10 );
11});
12
13function MissionDashboard({ missions }) {
14 const [filter, setFilter] = useState('all');
15 const [selectedId, setSelectedId] = useState(null);
16
17 // Musisz pamietac o useMemo...
18 const filteredMissions = useMemo(
19 () => missions.filter(m => filter === 'all' || m.status === filter),
20 [missions, filter]
21 );
22
23 // ...i o useCallback dla kazdej funkcji przekazywanej jako prop
24 const handleSelect = useCallback((id) => {
25 setSelectedId(id);
26 }, []);
27
28 return (
29 <div>
30 {filteredMissions.map(m => (
31 <MissionCard key={m.id} mission={m} onSelect={handleSelect} />
32 ))}
33 </div>
34 );
35}Problemy z reczna memoizacja:
useCallback i React.memo nie zadzialauseMemo/useCallback = bugReact Compiler to narzedzie budowania (build-time tool), ktore automatycznie analizuje komponenty React i dodaje odpowiednia memoizacje. Dziala na etapie kompilacji - Twoj kod zrodlowy pozostaje czysty:
1// PO React Compiler - piszesz zwykly, czysty kod
2function MissionDashboard({ missions }) {
3 const [filter, setFilter] = useState('all');
4 const [selectedId, setSelectedId] = useState(null);
5
6 // Compiler AUTOMATYCZNIE memoizuje to obliczenie
7 const filteredMissions = missions.filter(
8 m => filter === 'all' || m.status === filter
9 );
10
11 // Compiler AUTOMATYCZNIE stabilizuje te funkcje
12 const handleSelect = (id) => {
13 setSelectedId(id);
14 };
15
16 return (
17 <div>
18 {filteredMissions.map(m => (
19 <MissionCard key={m.id} mission={m} onSelect={handleSelect} />
20 ))}
21 </div>
22 );
23}
24
25// Nie potrzebujesz React.memo - Compiler sam to ogarnie!
26function MissionCard({ mission, onSelect }) {
27 return (
28 <div onClick={() => onSelect(mission.id)}>
29 <h3>{mission.name}</h3>
30 <p>Status: {mission.status}</p>
31 </div>
32 );
33}Compiler analizuje Twoj kod podczas budowania (np. z Babel pluginem) i generuje zoptymalizowana wersje:
1// Twoj kod zrodlowy (co piszesz):
2function StarList({ stars, highlight }) {
3 const visible = stars.filter(s => s.magnitude < 6);
4 const style = { color: highlight ? '#ffd700' : '#ccc' };
5
6 return (
7 <ul style={style}>
8 {visible.map(s => <li key={s.id}>{s.name}</li>)}
9 </ul>
10 );
11}
12
13// Co Compiler generuje (uproszczony przyklad):
14function StarList_compiled({ stars, highlight }) {
15 // Compiler dodaje cache na filtrowanie
16 const visible = useMemo(
17 () => stars.filter(s => s.magnitude < 6),
18 [stars]
19 );
20
21 // Compiler cachuje obiekt style
22 const style = useMemo(
23 () => ({ color: highlight ? '#ffd700' : '#ccc' }),
24 [highlight]
25 );
26
27 return (
28 <ul style={style}>
29 {visible.map(s => <li key={s.id}>{s.name}</li>)}
30 </ul>
31 );
32}Compiler robi to inteligentnie - nie memoizuje wszystkiego, tylko te czesci, ktore faktycznie moga sie powtarzac z tymi samymi danymi.
1// babel.config.js
2module.exports = {
3 plugins: [
4 ['babel-plugin-react-compiler', {
5 compilationMode: 'infer',
6 panicThreshold: 'NONE',
7 }],
8 ],
9};1// next.config.js
2module.exports = {
3 experimental: {
4 reactCompiler: true,
5 },
6};infer (domyslny) - Compiler sam decyduje ktore komponenty optymalizowacannotation - optymalizuje tylko komponenty oznaczone dyrektywa 'use memo'all - optymalizuje wszystkie komponenty (najbardziej agresywny)React Compiler dziala poprawnie TYLKO jesli Twoj kod przestrzega "Rules of React":
1// DOBRZE - czysta funkcja, brak efektow ubocznych w renderze
2function GoodComponent({ data }) {
3 const sorted = [...data].sort((a, b) => a.name.localeCompare(b.name));
4 return <ul>{sorted.map(d => <li key={d.id}>{d.name}</li>)}</ul>;
5}
6
7// ZLE - mutacja props (Compiler moze wygenerowac bledny kod!)
8function BadComponent({ data }) {
9 data.sort((a, b) => a.name.localeCompare(b.name)); // Mutacja!
10 return <ul>{data.map(d => <li key={d.id}>{d.name}</li>)}</ul>;
11}
12
13// ZLE - efekt uboczny w renderze
14function BadComponent2({ userId }) {
15 // Compiler zalozy ze to jest czyste i moze je pominac!
16 analytics.track('render', userId);
17 return <div>User: {userId}</div>;
18}Kluczowe zasady:
useEffect, event handlerach lub callbackachReact Compiler wymaga przestrzegania zasad. ESLint plugin pomaga je egzekwowac:
1// .eslintrc.js
2module.exports = {
3 plugins: ['react-compiler'],
4 rules: {
5 'react-compiler/react-compiler': 'error',
6 },
7};Jesli masz istniejacy projekt z reczna memoizacja, mozesz stopniowo migrowac. Istniejace
React.memo i useMemo nie beda kolidowac z Compilerem - po prostu stanowia dodatkowa, zbedna warstwe.React Compiler to przyszlosc optymalizacji React:
useMemo, useCallback, React.memo za CiebiePamietaj: React Compiler to jak autopilot na statku kosmicznym - zrobi swoja prace doskonale, ale wymaga, zeby statek byl prawidlowo zbudowany.