Razumevanje Renderovanja i Rerenderovanja u React Aplikacijama: Kako funkcionišu i kako ih optimizovati

Jelena Petkovic - Sep 14 - - Dev Community

Kada kreiramo aplikacije u React-u, često se suočavamo sa pojmovima renderovanje (rendering) i rerenderovanje (re-rendering) komponenata. Iako ovo na prvi pogled može delovati jednostavno, stvari postaju zanimljive kada se upetljaju različiti state menadžment sistemi poput useState, Redux, ili kada ubacimo lifecycle hook-ove poput useEffect. Ako želite da vaša aplikacija bude brza i efikasna, razumevanje ovih procesa je ključno.

Šta je Renderovanje?

Renderovanje je proces u kojem React prikazuje vaš korisnički interfejs (UI) na ekranu, bazirano na stanju (state-u) ili prosleđenim vrednostima (props). Kada se vaša komponenta prvi put prikazuje, to se zove prvo renderovanje.

Kako Funkcioniše Prvo Renderovanje (Initial Render)?

Kada se komponenta prvi put "montira" na DOM, evo šta se događa:

1. Inicijalizacija state-a:
Bilo da koristite useState, props ili Redux, inicijalni state komponente se kreira.

2. Render funkcija:
React prolazi kroz JSX kod i generiše virtuelni DOM baziran na trenutnom stanju.

3. Kreira virtuelni DOM (Virtual DOM) za trenutno stanje komponente.

4. Upoređivanje (diffing):
Virtuelni DOM se upoređuje sa pravim DOM-om (pošto je prvi render, svi elementi će biti potpuno prikazani).

5. Prikazivanje:
Komponenta se prikazuje na ekranu.
Jednom kada je komponenta prikazana, sledeći izazov je rerenderovanje.

Rerenderovanje (Re-render): Kada i Zašto?

Rerenderovanje se dešava svaki put kada se stanje ili props promene. Da li ste kliknuli na dugme koje menja broj na ekranu? Promenili ste vrednost u Redux store-u? Sve te akcije mogu dovesti do toga da React ponovo prikaže komponentu, i tu dolazi do rerenderovanja.

Kako Funkcioniše Rerenderovanje?

Detekcija promene state-a:

  • Kod useState, kada pozovete setState, React zna da treba da ažurira komponentu.

  • Kod Redux-a, kada se promeni vrednost u store, svaka komponenta povezana sa tim delom stanja se ponovo renderuje.

Trigger renderovanja:

Kada se stanje promeni, React kreira novi virtuelni DOM baziran na toj promeni.

Upoređivanje (diffing):

  • React upoređuje novi virtuelni DOM sa starim i izračunava koje promene treba primeniti. Ovo je jedan od načina na koji React optimizuje renderovanje.

Prikaz promena:

  • Nakon što su promene izračunate, React ih primenjuje na stvarni DOM. Tako se samo promenjeni delovi stranice ponovo prikazuju.

Koje Komponente Se Rerenderuju?

Nisu sve komponente pogođene svakom promenom. React rerenderuje samo one komponente koje:

Korisite lokalni state:
Ako koristite useState, komponenta se rerenderuje svaki put kada se pozove setState.

Koriste Redux state:
Ako vaša komponenta zavisi od Redux stanja (preko useSelector ili connect), biće ponovo renderovana kada se taj deo stanja promeni.

Koriste props:
Ako se props vrednost promeni, komponenta se ponovo renderuje sa novim vrednostima.

Optimizacija Rerenderovanja

Naravno, nije uvek idealno da se sve komponente bespotrebno ponovo renderuju. Ako želimo da aplikacija radi brzo i efikasno, evo nekoliko tehnika za optimizaciju:

1. Memoizacija Komponenti
React nudi funkcionalnost za memoizaciju komponenata preko React.memo. Ako vaša komponenta ne zavisi od promena props ili state-a, možete je "zapamtiti", pa će se ponovo renderovati samo kada se relevantne vrednosti promene.

Primer:

const MemoizedComponent = React.memo(MyComponent);

Enter fullscreen mode Exit fullscreen mode

2. Memoizacija Funkcija i Vrednosti

Da biste izbegli ponovno kreiranje funkcija ili vrednosti pri svakom renderu, koristite useCallback za memoizaciju funkcija i useMemo za memoizaciju vrednosti.

  • useCallback vam omogućava da memoizujete funkciju i sprečite njeno ponovno kreiranje sve dok se zavisnosti ne promene.

  • useMemo memoizuje rezultat funkcije, tako da se ne računa ponovo na svakom renderu.

Primer:

const increment = useCallback(() => {
  setCount(prevCount => prevCount + 1);
}, []);

const expensiveCalculation = useMemo(() => {
  return count * 2;
}, [count]);
Enter fullscreen mode Exit fullscreen mode

3. Redux Optimizacija

Ako koristite Redux, možete dodatno optimizovati aplikaciju pomoću memoizovanih selektora kao što je reselect. To omogućava da se izbegne ponovno renderovanje komponenata koje nisu pogođene promenom stanja.

Lifecycle Hook-ovi i Rerenderovanje

U klasičnim React klasama, koristili smo shouldComponentUpdate da kontrolišemo kada će se komponenta ponovo renderovati. U funkcionalnim komponentama, ovaj koncept se može simulirati pomoću useEffect i memoizacije.

Zaključak

Renderovanje i rerenderovanje su ključni za prikaz korisničkog interfejsa u React aplikacijama, ali pravilno razumevanje i optimizacija tih procesa može napraviti razliku između spore i super brze aplikacije. Ispravno korišćenje memoizacije, useCallback, useMemo, kao i pažljivo rukovanje Redux-om, pomaže da izbegnemo nepotrebne re-rendere i održimo naše aplikacije brzim i responzivnim.

Primer Koda: Renderovanje i Rerenderovanje u Akciji
Evo primera komponente koja koristi useState, Redux i memoizaciju da optimizuje renderovanje:

import React, { useState, useEffect, useCallback, useMemo } from 'react';
import { useSelector, useDispatch } from 'react-redux';

const MyComponent = () => {
  // Lokalni state
  const [count, setCount] = useState(0);

  // Redux state
  const reduxValue = useSelector(state => state.someValue);
  const dispatch = useDispatch();

  // Memoizacija funkcije kako bi se izbeglo ponovno kreiranje na svakom renderu
  const increment = useCallback(() => {
    setCount(prevCount => prevCount + 1);
  }, []);

  // Memoizacija izračunate vrednosti
  const expensiveCalculation = useMemo(() => {
    return count * 2;
  }, [count]);

  // Efekat koji se pokreće samo pri promeni reduxValue
  useEffect(() => {
    console.log("Redux value changed:", reduxValue);
  }, [reduxValue]);

  return (
    <div>
      <p>Count: {count}</p>
      <p>Expensive Calculation: {expensiveCalculation}</p>
      <button onClick={increment}>Increment</button>
      <button onClick={() => dispatch({ type: 'SOME_ACTION' })}>
        Dispatch Redux Action
      </button>
    </div>
  );
};
Enter fullscreen mode Exit fullscreen mode

Kao što vidimo, ovde se koristi kombinacija lokalnog state-a, Redux-a, memoizacije i useEffect hook-a da bi aplikacija bila što efikasnija.

. . . . . . . . .
Terabox Video Player