W poprzedniej lekcji omówiliśmy sobie, czym jest mount render (tzw. initial render) oraz diff render jak ja go nazywam (tzw. re-render). Dzisiaj omówimy sobie, co się dzieje przy dosłownie każdym renderze.
Przypomnijmy:
- mount render (initial render) – render wykonany po componentDidMount (React porzucił już OOP, to był zdaje się odpowiednik swego rodzaju connectedCallback z web components)
- diff-render:
- Gdy zmieni się stan komponentu
- Gdy zmieni się stan komponentu rodzica albo rodzic ma diff-render
- Gdy zmieni się kontekst
- każdy render = mount-render + diff-rendery
Ok, academind ma na swoim githubie taki oto kod:
import { useState, useCallback } from 'react';
import QUESTIONS from '../questions.js';
import Question from './Question.jsx';
import Summary from './Summary.jsx';
export default function Quiz() {
const [userAnswers, setUserAnswers] = useState([]);
const activeQuestionIndex = userAnswers.length;
const quizIsComplete = activeQuestionIndex === QUESTIONS.length;
const handleSelectAnswer = useCallback(function handleSelectAnswer(
selectedAnswer
) {
setUserAnswers((prevUserAnswers) => {
return [...prevUserAnswers, selectedAnswer];
});
},
[]);
const handleSkipAnswer = useCallback(
() => handleSelectAnswer(null),
[handleSelectAnswer]
);
if (quizIsComplete) {
return <Summary userAnswers={userAnswers} />
}
return (
<div id="quiz">
<Question
key={activeQuestionIndex}
index={activeQuestionIndex}
onSelectAnswer={handleSelectAnswer}
onSkipAnswer={handleSkipAnswer}
/>
</div>
);
}
Na razie wszystkiego nie ogarniemy, ale chciałby zaznaczyć kilka kwestii:
- Mount render i każdy diff-render będzie wywoływał ponowne przypisanie wartości do nowych w zasadzie stałych
- Gdyby ktoś chciał aby to wszystko nie było wyliczane od nowa przy każdym renderze, musiałby:
- albo wynieść te stałe powyżej poziomu RFC (nie w sensie „powyżej” Reacta tylko powyżej kodu JS, nad RFC, ale wtedy one nie mogłyby się nigdy zmieniać)
- albo użyć useMemo i wtedy te stałe będą keszowane i ponownie obliczane tylko wtedy, gdy zmienią się zależności
- Mamy też definicje funkcji, załóżmy, że useCallback nie ma
- Każda definicja funkcji wewnątrz RFC będzie tworzona od nowa, do zera, gdy nastąpi jakikolwiek render (mount render lub diff rendery)
- Jeżeli ktoś chciałby aby definicja funkcji nie była tworzona od zera, musiałby:
- Wynieść ją powyżej poziomu RFC (powyżej w sensie kodu JS, nie struktury komponentów React)
- Wynieść ją do innego pliku i zaimportować
- Jeżeli ma się zmieniać, ale tylko wtedy, gdy to konieczne, to używa się do tego useCallback z tablicą zależności
I mamy użycie useCallback:
- Pierwsza funkcja to handler, który ma pustą tablicę zależności, bo ta funkcja nie zmienia się nigdy – zawsze do setState wpuszcza poprzednie odpowiedzi + nową odpowiedź
- Druga funkcja polega na tej pierwszej, ale jeśli pierwsza się nie zmieni to druga też nie ulegnie zmianie – ma wpuszczać null jako nową odpowiedź, gdyby było skip answer
Ok, podsumujmy, co już wiemy, bo będzie nam to do następnej lekcji potrzebne:
- Mount wywołuje mount render
- Zmiana stanu wywołuje diff-render
- Zmiana stanu rodzica (diff-render rodzica) wywołuje diff render dziecka
- Jeżeli RFC ma memo, to diff render rodzica wywoła diff-render dziecka tylko wtedy, gdy przekazane zostaną inne propsy
- Każdy render wywołuje utworzenie nowych stałych/zmiennych wewnątrz RFC i przypisanie im wartości
- Jeżeli użyjemy useMemo, to każdy render będzie wywoływał utworzenie nowych stałych/zmiennych tylko wtedy, gdy zmienią się im zależności
- Każdy render wywołuje utworzenie nowych definicji funkcji wewnątrz RFC
- Jeżeli nie chcemy tworzyć od nowa definicji funkcji wewnątrz RFC to używamy useCallback i tablicy zależności
Ok, postarajmy się to zrozumieć, w następnych lekcjach temat będzie kontynuowany.