W poprzednich notkach pisałam już o React Compiler od podstaw — czym jest i jak działa (React Compiler – Kompletny Przewodnik), jak go podglądać w akcji (React Compiler Playground), a także jak pisać kod, który kompilator potrafi zoptymalizować (Jak pisać kod, który React Compiler potrafi zoptymalizować).
Czas zobaczyć, co się dzieje, gdy kod łamie Rules of React.
Przygotowałam w tym celu aplikację demo, którą możecie:
- 👀 podejrzeć na GitHub
- 🚀 uruchomić w przeglądarce na GitHub Pages
Aplikacja ma dwie sekcje:
- Good examples – kod, który dawniej wymagał memoizacji, ale React Compiler radzi sobie z nim automatycznie
- Bad examples – przykłady łamania Rules of React


Jeśli łamiemy te zasady, React Compiler może:
- zrezygnować z optymalizacji
- zgłosić błąd ESLint
- a w niektórych przypadkach nawet zablokować kompilację
Najlepiej widać różnicę w React Developer Tools. W sekcji Good examples wszystkie komponenty są auto-memoizowane ✨. W sekcji Bad examples — React Compiler rezygnuje z optymalizacji tam, gdzie kod łamie Rules of React.


Good examples – kiedy React Compiler robi robotę za nas
Pierwsza część aplikacji pokazuje kod, który dawniej wymagał ręcznej optymalizacji, ale React Compiler potrafi go zoptymalizować automatycznie.
Komponent bez React.memo
Przykład komponentu potomnego:
const ExpensiveChild = ({ count, onIncrement }) => {
return (
<div>
<p>Count: {count}</p>
<button onClick={onIncrement}>Increment count</button>
</div>
);
};
W klasycznym React często dodawalibyśmy:
export default React.memo(ExpensiveChild);
Dlaczego?
Ponieważ funkcja przekazywana w propsach zmienia referencję przy każdym renderze.
W naszej aplikacji wygląda to tak:
const handleIncrement = () => {
setCount(prev => prev + 1);
};
Dawniej bardzo często pojawiał się tu useCallback:
const handleIncrement = useCallback(() => {
setCount(prev => prev + 1);
}, []);
React Compiler potrafi jednak automatycznie ustabilizować funkcje, więc ręczne useCallback przestaje być potrzebne.
Obliczenia bez useMemo
W aplikacji znajduje się też kosztowna operacja wykonywana podczas renderu:
const filteredItems = items.filter(item => item.toLowerCase().includes(filter.toLowerCase()));
const expensiveCalculation = filteredItems.reduce((acc, item) => {
let result = 0;
for (let i = 0; i < 1000; i++) {
result += item.length;
}
return acc + result;
}, 0);
W klasycznym React często pojawiłoby się tutaj:
const expensiveCalculation = useMemo(() => {
...
}, [filteredItems]);
React Compiler potrafi jednak automatycznie memoizować takie obliczenia, jeśli są czyste i zależą tylko od danych wejściowych.
Bad examples – kiedy łamiemy Rules of React
Druga część aplikacji pokazuje przykłady kodu, który łamie Rules of React.
W takich sytuacjach React Compiler:
- nie może bezpiecznie zoptymalizować kodu
- zgłosi błąd ESLint
- albo całkowicie zablokuje kompilację
Warto wiedzieć, że od wersji 7 eslint-plugin-react-hooks zawiera zarówno klasyczne reguły hooków, jak i reguły React Compilera. Nie potrzebujemy już osobnego eslint-plugin-react-compiler.
Błąd numer 1 – warunkowe wywołanie hooka
if (showCount) {
const [count] = useState(0);
}
Hooki muszą być wywoływane zawsze w tej samej kolejności.
Nie mogą znajdować się w:
ifforwhile- funkcjach zagnieżdżonych
Wykrywane przez: react-hooks/rules-of-hooks
Błąd numer 2 – mutowanie propsów
data.value = 100;
Propsy w React powinny być traktowane jako immutable.
Wykrywane przez: react-hooks/immutability
Błąd numer 3 – efekty uboczne podczas renderu
externalStore.data['key'] = value;
Render komponentu powinien być czystą funkcją.
Efekty uboczne powinny znajdować się w useEffect.
Wykrywane przez: react-hooks/purity
Błąd numer 4 – bezpośrednia mutacja stanu
user.age = 26;
setUser(user);
Stan w React powinien być niemutowalny.
Poprawna wersja wyglądałaby tak:
setUser(prev => ({
...prev,
age: 26
}));
Wykrywane przez: react-hooks/immutability.
Błąd numer 5 – hook w pętli
for (let i = 0; i < items.length; i++) {
useState(items[i]);
}
Hooki nie mogą być wywoływane w pętlach
Wykrywane przez: react-hooks/rules-of-hooks
Błąd numer 6 – hook w funkcji zagnieżdżonej
function createState() {
const [count] = useState(0);
}
Hooki mogą być wywoływane tylko w:
- komponentach React
- custom hookach
Wykrywane przez: react-hooks/rules-of-hooks
Błąd numer 7 – brak zależności w useEffect
useEffect(() => {
console.log(value);
}, []);
Brakuje value w tablicy zależności. Warto wiedzieć, że React Compiler poprawnie memoizuje ten komponent — sam komponent jest czysty, a błąd dotyczy tylko logiki wewnątrz useEffect, co jest osobną kwestią.
Wykrywane przez: react-hooks/exhaustive-deps
Błąd numer 8 – komponent zdefiniowany w renderze
const InnerComponent = () => {
return <div>Inner count: {count}</div>;
};
Komponent tworzony przy każdym renderze utrudnia optymalizację.
Wykrywane przez: react-hooks/rules-of-hooks
Błąd numer 9 – mutowanie wartości używanej przez hooki
const [config] = useState({ enabled: true });
config.enabled = false;
Mutowanie wartości zwróconej przez hook łamie założenia React Compiler.
Wykrywane przez: react-hooks/immutability
Podsumowanie przykładów
| Issue | Problem | Reguła ESLint |
|---|---|---|
| 1 | Conditional hooks | react-hooks/rules-of-hooks |
| 2 | Props mutation | react-hooks/immutability |
| 3 | Side effects during render | react-hooks/purity |
| 4 | State mutation | react-hooks/immutability |
| 5 | Hook inside loop | react-hooks/rules-of-hooks |
| 6 | Hook inside nested function | react-hooks/rules-of-hooks |
| 7 | Missing effect dependencies | react-hooks/exhaustive-deps |
| 8 | Component inside render | react-hooks/rules-of-hooks |
| 9 | Mutating hook value | react-hooks/immutability |
Rola eslint-plugin-react-hooks
Od wersji 7 eslint-plugin-react-hooks zawiera wszystkie potrzebne reguły:
react-hooks/rules-of-hooks— błędy numer 1, 5, 6, 8react-hooks/exhaustive-deps— błąd numer 7react-hooks/immutability— błędy numer 2, 4, 9react-hooks/purity— błąd numer 3
Podsumowanie
React Compiler może automatycznie zastąpić wiele rzeczy, które wcześniej robiliśmy ręcznie:
React.memouseMemouseCallback
Ale działa najlepiej wtedy, gdy kod jest:
- zawsze zwraca ten sam wynik dla tych samych danych wejściowych
- nie mutuje propsów ani stanu bezpośrednio
- przestrzega Rules of React
Jeśli łamiemy te zasady, kompilator może:
- zgłosić błąd ESLint
- zrezygnować z optymalizacji
- albo zablokować kompilację.
Dlatego jeśli chcecie w pełni wykorzystać możliwości React Compiler, warto upewnić się, że Wasz kod przestrzega tych zasad.


