- React.js: Wprowadzenie do kursu od podstaw
- Poznaj React.js
- Pierwszy komponent w React.js
- Props czyli atrybuty w React.js
- Podział na komponenty w React.js
- Klasy jako komponenty React.js
- Interakcja z komponentami React.js
- Stan komponentów React.js
- State w React.js 2
- Metody cyklu życia komponentu w React.js
- React.js w przykładach: filtrowanie statycznej listy
- Tworzenie aplikacji React.js dzięki create-react-app
- React.js na GitHub Pages dzięki create-react-app
- Testowanie aplikacji React.js — podstawy Enzyme
- Testowanie React.js w Enzyme — props, state i interakcje
- Poprawne bindowanie funkcji w React.js
- Odpowiadam na pytania: Babel, ECMAScript, destrukturyzacja, onClick, className
- Komunikacja pomiędzy komponentami w React.js
- Komunikacja z API w React.js
- Formularze w React.js — kontrolowane komponenty
- Formularze w React.js — niekontrolowane komponenty
- Odpowiadam na pytania: props, nawiasy klamrowe, funkcje vs klasy, import react
- TDD w React.js z pomocą react-testing-library
- Flux i Redux: globalny store i jednokierunkowy przepływ danych
- React + Redux — kurs: wprowadzenie i podstawy
- React + Redux — filtrowanie listy, proste selektory
- Projektowanie komponentów: Presentational & Container Components
- Asynchroniczność w Redux: redux-thunk
- Kiedy używać state, a kiedy Redux?
- Nowe metody cyklu życia: getDerivedStateFromProps i getSnapshotBeforeUpdate
- Leniwe ładowanie komponentów w React dzięki import
- Higher Order Reducers — Redux i powtarzanie kodu
- React Hooks — wprowadzenie i motywacja
- React Hooks: useState, czyli stan w komponentach funkcyjnych
- React Hooks: useState — wiele stanów, callbacki i inne niuanse
- React Hooks: useEffect — efekty uboczne w komponencie
- React Hooks a żądania do API
- useReducer — przenoszenie logiki poza komponent
- useMemo, useCallback, czyli rozwiązanie problemów ze zmieniającymi się propsami
- Wady React Hooks
- React Hooks: Piszemy własne hooki!
Powszechnym zmartwieniem osób poznających komponenty funkcyjne jest tworzenie funkcji-callbacków przekazywanych dalej jako props. Wszak przy każdym renderze funkcja tworzona jest na nowo! Czy to aby nie marnotrastwo? Czy nie powoduje to problemów? React Hooks useMemo
i useCallback
przychodzą na ratunek!
Problem z funkcjami
Weźmy prosty komponent, w którym tworzony jest callback handleClick
przekazywany jako props dalej:
function MyComponent({ oneProp, anotherProp }) {
function handleClick() {
console.log('Clicked!', oneProp, anotherProp);
}
return <SpecialButton onClick={handleClick} />;
}
Gdy ja pierwszy raz zobaczyłem taki kod, miałem mnóstwo wątpliwości — Ale po co? Dlaczego? Jak to? Przecież to nie ma sensu! Chętnie odpowiem Ci na te pytania osobiście: Poznaj React w dwa dni na naszym szkoleniu!
Przede wszystkim, tworzenie nowej funkcji handleClick
za każdym razem, gdy renderowany jest komponent wydawało mi się barbarzyństwem. Czy to aby nie ma tragicznego wpływu na wydajność?
No i dodatkowo, tworzymy nową funkcję, więc jako props do komponentu SpecialButton
przekazywana jest zawsze nowa referencja. Oznacza to, że zostanie on przerenderowany za każdym razem.
Problemy z obiektami
Analogiczna sytuacja występuje, o czym wiele osób zdaje się nie myśleć, gdy w renderze tworzymy nowy obiekt:
function MyComponent({ oneProp, anotherProp }) {
const options = {
data: oneProp,
data2: anotherProp,
// …
};
return <SpecialComponent options={options} />;
}
Za każdym razem options
tworzone jest na nowo, i jest nową referencją. Po przekazaniu tego obiektu jako props do SpecialComponent
, ten przerenderuje się za każdym razem.
useCallback
Jest taki React Hook, który rozwiązuje pierwszy problem! Nazywa się useCallback
. Jako pierwszy argument przyjmuje funkcję, a jako drugi taką samą tablicę zależności, jak useEffect
.
function MyComponent({ oneProp, anotherProp }) {
const handleClick = React.useCallback(() => {
console.log('Clicked!', oneProp, anotherProp)
}, [oneProp, anotherProp]);
return <SpecialButton onClick={handleClick} />;
}
W ten sposób, funkcja przekazana do React.useCallback
jest memoizowana. To znaczy, że dopóki nie zmienią się oneProp
lub anotherProp
, dopóty handleClick
nie będzie nową funkcją.
React.useCallback
zapamiętuje stworzoną funkcję i dzięki temu komponent SpecialButton
nie przerenderuje się bez potrzeby!
useMemo
To React Hook, który zwraca zapamiętaną wartość. W pewnym sensie, to uogólniona wersja useCallback
. Jako argument przyjmuje funkcję, która zwraca wartość.
function MyComponent({ oneProp, anotherProp }) {
const options = useMemo(() => ({
data: oneProp,
data2: anotherProp,
// …
}), [oneProp, anotherProp]);
return <SpecialComponent options={options} />;
}
W ten sposób obiekt options
będzie za każdym razem tą samą referencją i komponent SpecialComponent
nie będzie musiał się przerenderowywać — przynajmniej dopóki nie zmieni się oneProp
lub anotherProp
!
Czy Hooki useCallback i useMemo nie są zbędne?
Napisałem, że React Hook useMemo
to trochę uogólniona wersja useCallback
— i to prawda. useCallback
jest funkcjonalnie równoważny takiemu zapisowi:
const myUseCallback = (fn, deps) => useMemo(() => fn, deps)
Kiedy używać
Z rozsądkiem 😉 Nie powiem Ci dokładnie kiedy, ale ja bym używał zawsze, gdy może być z tego jakiś zysk, a nie ma negatywnego wpływu na czytelność.
Pytania?
Jeśli chcesz na bieżąco śledzić kolejne części kursu React.js to koniecznie polub mnie na Facebooku i zapisz się na newsletter.
- React.js: Wprowadzenie do kursu od podstaw
- Poznaj React.js
- Pierwszy komponent w React.js
- Props czyli atrybuty w React.js
- Podział na komponenty w React.js
- Klasy jako komponenty React.js
- Interakcja z komponentami React.js
- Stan komponentów React.js
- State w React.js 2
- Metody cyklu życia komponentu w React.js
- React.js w przykładach: filtrowanie statycznej listy
- Tworzenie aplikacji React.js dzięki create-react-app
- React.js na GitHub Pages dzięki create-react-app
- Testowanie aplikacji React.js — podstawy Enzyme
- Testowanie React.js w Enzyme — props, state i interakcje
- Poprawne bindowanie funkcji w React.js
- Odpowiadam na pytania: Babel, ECMAScript, destrukturyzacja, onClick, className
- Komunikacja pomiędzy komponentami w React.js
- Komunikacja z API w React.js
- Formularze w React.js — kontrolowane komponenty
- Formularze w React.js — niekontrolowane komponenty
- Odpowiadam na pytania: props, nawiasy klamrowe, funkcje vs klasy, import react
- TDD w React.js z pomocą react-testing-library
- Flux i Redux: globalny store i jednokierunkowy przepływ danych
- React + Redux — kurs: wprowadzenie i podstawy
- React + Redux — filtrowanie listy, proste selektory
- Projektowanie komponentów: Presentational & Container Components
- Asynchroniczność w Redux: redux-thunk
- Kiedy używać state, a kiedy Redux?
- Nowe metody cyklu życia: getDerivedStateFromProps i getSnapshotBeforeUpdate
- Leniwe ładowanie komponentów w React dzięki import
- Higher Order Reducers — Redux i powtarzanie kodu
- React Hooks — wprowadzenie i motywacja
- React Hooks: useState, czyli stan w komponentach funkcyjnych
- React Hooks: useState — wiele stanów, callbacki i inne niuanse
- React Hooks: useEffect — efekty uboczne w komponencie
- React Hooks a żądania do API
- useReducer — przenoszenie logiki poza komponent
- useMemo, useCallback, czyli rozwiązanie problemów ze zmieniającymi się propsami
- Wady React Hooks
- React Hooks: Piszemy własne hooki!
No i to są argumenty, które sprawiają, że hooki wcale nie są takie różowe. Przez te dodatkowe wrappery bardzo łatwo jest stworzyć spaghetti, a żeby nie tworzyć spaghetti, trzeba więcej zastanawiać się, jak to wszystko napisać.
Napisałem prosty projekt w hookach i bardzo mnie od siebie odrzucił takie rozwiązanie 🙂 jak dla mnie, komponenty klasowe ftw 🎉
Początkowo się zgodziłem w myślach z tym komentarzem. Rzeczywiście, w niektórych przypadkach klasy tutaj będą ładniejsze. Ale nie zawsze!
Weźmy przykład z Context API. Mamy Provider, przekazujemy do niego value, które jest obiektem.
Pytanie: Jak można łatwo cache’ować ten obiekt w klasie, aby komponenty niepotrzebnie się nie przerenderowywały? Jest to trudne i brzydkie. W funkcjach tego problemu nie ma, useMemo i po kłopocie.
Na pewno należy używać z rozwagą ale stwierdzenie, że „zawsze” bo nie ma negatywnego wpływu jest mocno przesadzone 🙂
Zapraszam do artykułu: https://kentcdodds.com/blog/usememo-and-usecallback
Przykład z artykułu nie ma sensu, bo do onClick i tak przekazywana jest zawsze nowa funkcja strzałkowa. W związku z czym użycie funkcji useCallback jest całkowicie bezcelowe i niepoprawne.
W praktycznie każdym innym przypadku będzie zysk na wydajności.
Trzeba brać poprawkę na „guru” i zawsze samemu weryfikować treści 🙂
[…] useMemo, useCallback, czyli rozwiązanie problemów ze zmieniającymi się propsami […]