Używamy cookies, żeby zwiększyć Twoje doświadczenia na stronie
CodeWorlds

React Compiler (React Forget)

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.

Problem: reczna memoizacja

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:

  • Latwo zapomniec - pominiesz
    useCallback
    i
    React.memo
    nie zadziala
  • Boilerplate - duzo kodu, ktory nie dotyczy logiki biznesowej
  • Bledne zaleznosci - zly dependency array w
    useMemo
    /
    useCallback
    = bug
  • Nadmierna memoizacja - memoizujesz rzeczy, ktore nie potrzebuja optymalizacji

React Compiler - automatyczna memoizacja

React 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}

Jak dziala React Compiler?

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.

Konfiguracja React Compiler

Instalacja z Babel

1// babel.config.js
2module.exports = {
3  plugins: [
4    ['babel-plugin-react-compiler', {
5      compilationMode: 'infer',
6      panicThreshold: 'NONE',
7    }],
8  ],
9};

Instalacja z Next.js

1// next.config.js
2module.exports = {
3  experimental: {
4    reactCompiler: true,
5  },
6};

Tryby kompilacji

  • infer
    (domyslny) - Compiler sam decyduje ktore komponenty optymalizowac
  • annotation
    - optymalizuje tylko komponenty oznaczone dyrektywa
    'use memo'
  • all
    - optymalizuje wszystkie komponenty (najbardziej agresywny)

Zasady React (Rules of React)

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:

  1. Komponenty musza byc czystymi funkcjami - ten sam input = ten sam output
  2. Nie mutuj props ani state bezposrednio
  3. Efekty uboczne tylko w
    useEffect
    , event handlerach lub callbackach
  4. Nie czytaj refs podczas renderowania (tylko w efektach i handlerach)

ESLint plugin

React 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};

Migracja istniejacego kodu

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.

Podsumowanie

React Compiler to przyszlosc optymalizacji React:

  1. Automatyczna memoizacja - Compiler dodaje
    useMemo
    ,
    useCallback
    ,
    React.memo
    za Ciebie
  2. Czystszy kod - piszesz prostszy, latwiejszy do utrzymania kod
  3. Mniej bledow - Compiler nie zapomni o dependency array
  4. Build-time - zero kosztu runtime, optymalizacje na etapie kompilacji
  5. Wymaga czystego kodu - komponenty musza przestrzegac Rules of React

Pamietaj: React Compiler to jak autopilot na statku kosmicznym - zrobi swoja prace doskonale, ale wymaga, zeby statek byl prawidlowo zbudowany.

Przejdź do CodeWorlds