Strona główna / Artykuły / Przewodnik po rozmowach kwalifikacyjnych z React: hooksy, renderowanie i to, o co pytają duże firmy.

Przewodnik po rozmowach kwalifikacyjnych z React: hooksy, renderowanie i to, o co pytają duże firmy.

Wirtualny DOM, pułapki związane z hooksami, wydajność, zarządzanie stanem, React 18, ćwiczenia z kodowaniem na żywo oraz sposoby wyjaśniania przyczyn ponownego renderowania.

1332 słów

Podczas rozmów rekrutacyjnych z React w dużych firmach rzadko ocenia się umiejętność deklamacji dokumentacji. Zamiast tego sprawdza się, czy kandydat rozumie mechanizmy działania – dlaczego komponent jest renderowany ponownie, dlaczego efekt uruchamia się dwa razy, dlaczego aktualizacja stanu nie pojawia się natychmiast. Kandydaci, którzy potrafią wyjaśnić dlaczego, przewyższają tych, którzy znają tylko jak.

Poniżej przedstawiono typowe tematy, które faktycznie pojawiają się podczas rozmów: podstawy, hooks, wydajność, wzorce projektowe oraz trudne pytania, które pojawiają się wszędzie.

1. Podstawowe zasady

Pytania wprowadzające prawie zawsze dotyczą:

  • Virtual DOM – czym jest i dlaczego aktualizacje wydają się szybsze (porównywanie różnic zamiast bezpośrednich zmian w DOM).
  • Reconciliation – jak React decyduje, co aktualizować (klucze, sprawdzanie typu elementu).
  • JSX – „cukierkowy” język, który kompiluje się do React.createElement(); trzeba to dobrze znać.
  • Kontrolowane vs niekontrolowane — dane kontrolowane są powiązane ze stanem React (value + onChange); te niekontrolowane odczytują DOM za pośrednictwem refów.
  • Props vs stan — props są tylko do odczytu i przekazywane z góry; stan jest lokalny i zmieniany za pomocą funkcji setterów/hooków.
  • Klucze listy — użycie indeksu jako klucza powoduje problemy przy zmianie kolejności (niewłaściwe ponowne użycie DOM/stanu).
  • Zadanie na podstęp: „Dlaczego nie użyć indeksu tablicy jako klucza?” Odpowiedz konkretnym przykładem przestawienia lub dodania elementu, w którym React przypisuje stan do niewłaściwego wiersza.

    2. Hooks (najbardziej złożona część rozmowy kwalifikacyjnej)

    useState

    • Zaktualizowania są asynchroniczne lub grupowane.
    • Zastarzałe zamknięcia: kilka wywołań setCount(count + 1) w jednym zdarzeniu dzieli się tym samym wartością count; setCount(prev => prev + 1) rozwiązuje ten problem.

    useEffect

    • Zależności: [] raz, pomijane przy każdym renderowaniu, wyświetlane tylko gdy ulegną zmianie.
    • Czas i cel czyszczenia (wycieki pamięci, anulowanie subskrypcji/pobierania danych).
    • Dlaczego efekty działają dwa razy w trybie rozwojowym — Strict Mode w React 18 wywołuje funkcje dwukrotnie, aby ujawnić brakujące czyszczenie. Prawie wszyscy napotykają to problem raz.

    useMemo vs useCallback

    • useMemo przechowuje w pamięci wartość; useCallback przechowuje w pamięci tożsamość funkcji.
    • Oba zapewniają równość referencyjną dla dzieci funkcji React.memo lub tablic zależności.
    • Nadużywanie ma swoje konsekwencje; rozmówcy o pracę lubią słyszeć, że memozacja nie jest bezkosztowa.

    useRef

    • Zmienna wartość pomiędzy renderowaniami bez ponownego renderowania.
    • Węzły DOM, poprzednie wartości, identyfikatory timerów.

    useContext

    • Zakończa wiercenie właściwości dla poddrzewa.
    • Uwaga: aktualizacja kontekstu ponownie renderuje każdego konsumenta w poddrzewie, włączając te, które czytają tylko jedno pole.

    useReducer

    • Należy go preferować, gdy logika jest złożona lub kilka pól aktualizuje się jednocześnie (lokalne reduktory w stylu Redux).

    Custom hooks

    • Bądź gotowy do pisania funkcji takich jak useDebounce, useFetch lub useLocalStorage „na żywo” – to jeden z najczęściej spotykanych praktycznych ćwiczeń.

    3. Renderowanie i wydajność

    Tutaj osoby o poziomie średnim i wyższym oddzielają się od siebie.

    • Dlaczego ponownie renderować? Ponieważ renderuje się element rodzicielski, zmienia się stan, kontekst lub właściwości, które wyglądają tak samo, ale są nowymi referencjami.
    • React.memo – porównanie właściwości na poziomie powierzchniowym; bezużyteczne, jeśli za każdym razem przekazuje się nowe obiekty/funkcje (należy je łączyć z useMemo/useCallback).
  • Dzielenie kodu — React.lazy + Suspense.
  • Wirtualizacja — wirtualizacja w stylu react-window dla bardzo długich list.
  • Mniej ponownych renderowań — przenoszenie stanu na niższy poziom, dzielenie kontekstów, celowe używanie memoizacji.
  • Profiler — mierzenie zamiast domyślania się.
  • Klasyczne pytanie: lista z 10 000 wierszami zwalnia podczas wpisywania zapytania wyszukiwania. Należy oczekiwać funkcji debounce, wirtualizacji oraz wierszy zastosowanych memoizacji.

    4. Zarządzanie stanem

    • Stan lokalny, globalny i serwerowy — odrębne nazewnictwo stanu serwerowego (cache, revalidate, loading/error) od stanu interfejsu robi dobre wrażenie na ekspertach.
    • Context vs Redux/Zustand — Context do rzadko używanych globalnych wartości (temat, autoryzacja); Redux/Zustand, gdy potrzebne są middleware, narzędzia, złożone aktualizacje lub częste zapisy bez problemów związanych z Contextem.
    • React Query / SWR / TanStack Query — buforowanie, ponowne pobieranie w tle, usuwanie duplikatów, aby uniknąć ponownego tworzenia mechanizmu pobierania danych z useEffect.
    • Podstawy Redux (jeśli stos go używa): akcje, reduktory, magazyn danych, middleware typu thunk/saga, czyste reduktory.

    5. Wzorce projektowe

    • HOCs — otaczanie komponentu; klasyczny przykład withAuth.
    • Render props — współdzielenie logiki za pomocą funkcji jako właściwości; w większości przypadków zastąpione przez haki, ale koncepcja ta nadal jest istotna.
    • Komponenty złożone — komponenty siostrzane dzielące się stanem za pośrednictwem kontekstu (Select / Select.Option).
    • Komponenty kontenerowe/prezentacyjne — dane vs interfejs użytkownika; z hakami separacja jest mniej sztywna, ale nadal ma znaczenie.
    • Kompozycja zamiast dziedziczenia — preferowana metoda ponawnego użycia w React; bądź gotów ją uzasadnić.

    6. Życiowy cykl klasy (nadal często pytane)

    Firmy, które wciąż preferują hooksy, badają nadal podstawy lub starsze bazy kodu.

    • componentDidMount ≈ useEffect(() => {}, [])
    • componentDidUpdate ≈ efekt z zależnościami
    • componentWillUnmount ≈ czyszczenie efektów
    • Grenice błędów — dostępne tylko dla klas (componentDidCatch / getDerivedStateFromError); hooksy nie mają odpowiednika, dlatego istnieją takie wrapperzy jak react-error-boundary.

    7. Znajomość React 18+

    • Renderyzacja równoległa — możliwość przerwania operacji dla bardziej responsywnego interfejsu.
    • useTransition — oznaczanie niepilnych aktualizacji, aby pisanie pozostawało szybkie.
    • useDeferredValue — opóźnienie niekrytycznych elementów interfejsu użytkownika.
    • Automaticzne grupowanie zadań — grupowanie operacji wewnątrz obietnic, timeoutów oraz rdzennych obsług (nie tylko obsług React).
    • Suspense dla danych — szczególnie przydatne w architekturach typu Next.js/Remix.
    • Komponenty serwerowe — gdzie i co się uruchamia oraz dlaczego pliki klienta są mniejsze.

    8. JavaScript, który się zakrada

    • Zamknięcia funkcji — przestarzały stan hooków.
    • Pętla zdarzeń / zadania mikro i makro — dlaczego grupowanie zadań działa w ten sposób.
    • Przypisywanie wartości this — w przypadku, gdy używane są klasy.
    • Debounce vs throttle — praktycznie zawsze proponowane jako rozwiązanie na „optymalizację pola wyszukiwania”.
    • Porównanie powierzchowne vs głębokie — React.memo / useMemo oraz dlaczego literale obiektów uniemożliwiają memoizację.
      • Promises / async-await — problemy z jednoczesnym wykonywaniem zapytań, gdy użytkownicy szybko piszą.

      9. Testowanie

      • Testing Library — skupienie na zachowaniu aplikacji, a nie na jej wewnętrznej strukturze (zapytania dotyczące ról i tekstu).
      • Jest — symulowanie API; znajomość ograniczeń związanych ze zdjęciami stanu aplikacji.
      • Testy jednostkowe, integracyjne i end-to-end oraz miejsce, w którym zazwyczaj znajdują się testy komponentów.

      10. Kodowanie na żywo z powtarzaniem

      • Wyszukiwanie i autodopisywanie z opóźnieniem
      • Sprawdzony kod useFetch z obsługą stanu ładowania, błędów i danych
      • Przewijanie nieskończone lub paginacja
      • Okna modalne za pomocą portalu (createPortal) oraz powód ich istnienia (unikanie przepełnienia ekranu i problemów z wartością z-index przy jednoczesnym pozostawaniu w drzewie React dla obsługi zdarzeń i kontekstu)
      • Licznik z funkcjami cofnięcia i przywrócenia za pomocą useReducer
      • Zadanie „znajdź błąd” dotyczące przestarzałych zamykaczy funkcji lub brakujących zależności

      Przykładowe omówienie

      „Dlaczego ten useEffect tworzy nieskończony pętlę?”

      useEffect(() => {
        setData({ ...data, updated: true });
      }, [data]);
      

      Odpowiedź na poziomie eksperta: efekt wymienia data jako zależność, a następnie zapisuje do data nowy obiekt, dzięki czemu przy każdym uruchomieniu zmienia się zależność i efekt jest natychmiast ponownie uruchamiany. Rozwiązaniem jest usunięcie data z listy zależności w sytuacjach, gdy nie powinien on powodować ponownego uruchomienia, przeniesienie operacji aktualizacji poza efekt lub użycie funkcjonalnego aktualizatora z ściślejszą listą zależności.

      To, co odróżnia dobre odpowiedzi na pytania z React podczas rozmowy kwalifikacyjnej, to wyjaśnienie dlaczego coś się psuje – a nie tylko proponowanie poprawki.

      Zakończenie

      Głębia zrozumienia przewyższa pamiętanie powierzchni API. Pracodawcy chcą znać zachowanie renderowania, zasady działania zamknięć funkcji oraz kompromisy dotyczące wydajności – te błędy, które pojawiają się w produkcji. Przygotuj się, tworząc małe komponenty, które celowo zawodzą (stare zamknięcia funkcji, brakujące zależności, marnotrawne ponowne renderowanie), i naprawiając je. To właśnie ten instynkt debugowania jest tym, co faktycznie ocenia się podczas rozmowy kwalifikacyjnej.

      Gdy ćwiczysz, ogranicz sobie czas tak jak to robi się podczas rozmów kwalifikacyjnych: wyjaśnij zasady działania Virtual DOM w sześćdziesięciu sekundach, następnie napraw błąd związany ze starym zamknięciem funkcji, a potem zaprojektuj mechanizm opóźnionych zapytań. Taka kolejność odpowiada temu, w jaki sposób faktycznie przebiegają takie rozmowy.

      Jak zazwyczaj eskalują rozmowy kwalifikacyjne

      Rozgrzewki dotyczą Virtual DOM, kontrolowanych wprowadzeń i klawiszy. W środkowej fazie omawiane są hooki: zgrupowane aktualizacje, problem podwójnych efektów w trybie Strict Mode, memo versus callback oraz tworzenie własnego hooka na żywo. W zaawansowanej fazie skupiamy się na kwestiach wydajności – listach z dziesięcioma tysiącami wierszy, problemie context thrash, dowodach uzyskanych za pomocą Profilera – oraz na wyborze architektury pomiędzy Context, Redux/Zustand a TanStack Query do zarządzania stanem serwera.

      Zachowaj osobisty repozytorium z elementami „celowo uszkodzonymi”: licznik stale-closure, efekt braku zależności, zmemorizowana lista, która nadal jest renderowana ze względu na obiekty inline, oraz modal typu portal. Wyjaśnienie tych czterech napraw na głos obejmuje zaskakująco dużą część czasu poświęconego na programowanie na żywo i pracę przy tablicy.

      Jeśli w opisie stanowiska wspomniano React 18+, bądź przygotowany z jednym zdaniem na temat równoległego renderowania, przejść, wartości odroczonych, automatycznego grupowania aktualizacji oraz Server Components. Głębsza znajomość jednej konkretnej implementacji jest lepsza niż ogólne pojęcie o każdym RFC.

      Powiązane materiały

    • Potknięcia techniczne SEO w nowoczesnych frontendach JavaScript — renderowanie tylko na stronie klienta, niestabilne metadane, semantyka, CWV, błędy w plikach robots oraz dynamiczne trasy — rozwiązania dla zespołów inżynieryjnych.
    • Szybkość React zaczyna się od organizacji drzewa składników — ponowne renderowanie nie jest wrogiem – wrogiem jest szerokie rozprzestrzenianie się stanu. Przenieś źródła bliżej liści drzewa przed stosowaniem mikro-memorizacji.