Kluczowa rola „klucza” w mapowaniu tablic
Jeśli jesteś osobą, która ma tendencję do ignorowania komunikatu ostrzegawczego „każdy element powinien mieć unikalny klucz” podczas mapowania tablicy w React, ważne jest, aby poświęcić chwilę, aby zrozumieć, dlaczego to ostrzeżenie jest zgłaszane w pierwszej kolejności.
W React, podczas renderowania listy elementów za pomocą funkcji „Array.map()”, zaleca się podanie unikalnej właściwości „klucza” dla każdego elementu. Ale dlaczego?
Odpowiedzią jest optymalizacja.
Załóżmy, że budujemy sklep e-commerce, w którym mamy nasz koszyk i używamy tablicy do przechowywania produktów, które użytkownik dodał do swojego koszyka. Tablica może być dynamicznie aktualizowana, gdy użytkownik dodaje lub usuwa elementy.
Powiedzmy, że nasz drogi użytkownik kupuje nowiutkiego laptopa i aktualnie ma w koszyku 3 produkty, czyli 3 elementy tablicy.
Załóżmy teraz, że użytkownik dodaje do koszyka „ słuchawki” . Teraz, gdy przechowujemy tablicę w stanie, w momencie, gdy użytkownik doda lub usunie coś z tablicy, React ponownie wyrenderuje komponent, aby interfejs użytkownika mógł być zsynchronizowany z najnowszą wartością stanu tego konkretnego komponentu.
Zagra w grę „znajdź różnice”, aby dowiedzieć się, co się zmieniło od poprzedniego renderowania i odpowiednio zaktualizować interfejs użytkownika. Wykryje, że w bieżącym wirtualnym drzewie DOM jest nowy element, którego nie było w poprzednim wirtualnym drzewie DOM, i doda nowy element do DOM bez porównywania go z istniejącymi elementami w tablicy (to dlatego, że React porównał już wirtualne DOM-y i wie, że nowy element jest jedynym elementem, który się zmienił). Nie mamy słuchawek, więc je wkładamy. Bułka z masłem!
Więc teraz nasza tablica koszyków zostanie zmapowana w następujący sposób:
Ale teraz powiedzmy, że sklep pozwala użytkownikom sortować produkty w koszyku według ceny, od najniższej do najwyższej. W rezultacie zmienia się kolejność elementów w koszyku, a koszyk jest teraz wyświetlany w następujący sposób: mysz, słuchawki, klawiatura i laptop.
Tutaj React ponownie musi porównać cały wirtualny DOM, aby określić zmiany, ponieważ nie miał innego sposobu, aby dowiedzieć się, że elementy zostały po prostu ponownie uporządkowane i ani jeden element tablicy się nie zmienił . Wygeneruje nowe wirtualne drzewo DOM, które odzwierciedla nową kolejność elementów. Następnie porówna każdy element w poprzednim wirtualnym drzewie DOM z odpowiednim elementem w nowym wirtualnym drzewie DOM, aby określić zmiany.
Czy nie byłoby dobrze, gdyby React mógł znać różnicę między tym, kiedy elementy tablicy są po prostu zmienione, a kiedy faktycznie się zmieniły (dodane lub usunięte), a także dokładny element, który został dodany lub usunięty, abyśmy mogli zoptymalizować różnicowanie wirtualnego DOM przetwarzać i poprawiać wydajność?
Tak, możemy, a odpowiedź jest przez „kluczowy” rekwizyt.
Powiedzmy, że dodajemy klucz dla każdego elementu w naszej tablicy.
Kiedy więc React aktualizuje tablicę elementów, porównuje tylko klucze elementów w starej i nowej tablicy, aby określić, które elementy zostały dodane, usunięte lub przeniesione. React przeprowadzi bardziej szczegółowe porównanie zawartości elementów tylko wtedy, gdy klucze nie pasują do siebie lub jeśli nie określono żadnych kluczy (wczesne porównanie, w którym nie mieliśmy kluczy).
Tak więc w pewnym sensie React nadal dokonuje porównania podczas aktualizacji tablicy elementów, ale porównując klucze zamiast całej tablicy, może zoptymalizować proces aktualizacji i poprawić wydajność.
Porównanie z kluczami jest szybsze i wydajniejsze niż porównywanie całych elementów, ponieważ pozwala Reactowi szybko określić, które elementy zostały dodane, usunięte lub przeniesione. Pomaga to zminimalizować ilość pracy, którą React musi wykonać podczas aktualizacji i zapewnia, że aktualizacje są przetwarzane tak wydajnie, jak to tylko możliwe.
Dlaczego nie użyć indeksu jako kluczy?
Wywołanie zwrotne w funkcji array.map() przyjmuje parametr o nazwie index, który daje dostęp do wartości indeksu każdego elementu. Możemy ustawić klucz na indeks konkretnego elementu. Ale to wielkie nie!
function Component()
const cart = ["Laptop," "Headphones"];
return (
<div>
cart.map((eachItem, index) =>
return h1 key=index>eachItem/h1>;
})}
</div>
);
}
export default component;
React myśli w ten sposób: jeśli kluczowe właściwości elementu się nie zmieniły, nie muszę szczegółowo sprawdzać zawartości tego elementu. Zakładam, że jeśli klucz nie jest aktualizowany, to wszystko jest takie samo.
Math.random() — NIE!
Cóż, moglibyśmy pomyśleć, że użycie Math.random() dla kluczy jest dobrym pomysłem, ponieważ wygeneruje liczbę losową, która będzie unikalna wśród wszystkich kluczy w tej tablicy. Musimy jednak pamiętać, że przy każdym renderowaniu zostanie wygenerowany nowy klucz, nawet jeśli sama tablica się nie zmieniła . Może to spowodować, że React błędnie założy, że element został zmieniony lub dodany. To mija się z celem używania kluczy, ponieważ React nie może dokładnie porównać kluczy między renderami, aby zidentyfikować, które elementy faktycznie się zmieniły.
Tak więc regułą jest wybór klucza, który jest stabilny i spójny między renderowaniami, aby React mógł dokładnie porównywać klucze między renderowaniami, aby określić, które elementy zostały zmienione, dodane lub usunięte z tablicy. Więc — bez indeksu, bez matematyki. losowo() ❌