Tryb rygorystyczny

StrictMode jest narzędziem podkreślającym potencjalne problemy w aplikacji. Tak samo jak Fragment, StrictMode nie renderuje żadnego widocznego UI. Służy natomiast do aktywacji dodatkowych sprawdzeń i ostrzeżeń dla swoich potomków.

Uwaga:

Sprawdzenia dla trybu rygorystycznego są uruchamiane wyłącznie w trybie deweloperskim; nie mają one wpływu na build produkcyjny.

Możesz uruchomić tryb rygorystyczny dla jakiejkolwiek części swojej aplikacji. Dla przykładu:

import React from 'react';

function ExampleApplication() {
  return (
    <div>
      <Header />
      <React.StrictMode>
        <div>
          <ComponentOne />
          <ComponentTwo />
        </div>
      </React.StrictMode>
      <Footer />
    </div>
  );
}

W powyższym przykładzie sprawdzenia trybu rygorystycznego nie zostaną uruchomione dla komponentów Header i Footer. Zadziałają one natomiast dla ComponentOne i ComponentTwo oraz wszystkich ich potomków.

StrictMode aktualnie pomaga w:

Dodatkowe funkcjonalności zostaną dodane w przyszłych wydaniach Reacta.

Identyfikacja niebezpiecznych metod cyklu życia komponentu

Tak jak zostało to wytłumaczone w tym poście, niektóre stare metody cyklu życia komponentu nie są bezpiecznie dla asynchronicznych aplikacji reactowych. Jednakże jeżeli twoja aplikacja używa bibliotek firm trzecich, upewnienie się, że nie używa ona niebezpiecznych metod cyklu życia komponentu może być trudne. Na szczęście, tryb rygorystyczny może z tym pomóc!

Gdy tryb rygorystyczny jest włączony, React tworzy listę wszystkich komponentów klasowych, które używają niebezpiecznych metod cyklu życia, i loguje komunikaty ostrzegawcze z informacją o tych komponentach, jak na przykładzie:

strict mode unsafe lifecycles warning

Rozwiązanie teraz problemów zidentyfikowanych przez tryb rygorystyczny ułatwi użycie asynchronicznego renderowania w przyszłych wydaniach Reacta.

Ostrzeganiu o użyciu przestarzałego API tekstowych referencji

Poprzednio React umożliwiał zarządzanie referencjami na dwa sposoby: przestarzałe referencje tekstowe i funkcje zwrotne. Pomimo że referencja tekstowa była z tych dwóch wygodniejsza, miała kilka wad, dlatego też naszą oficjalną rekomendacją było używanie formy funkcji zwrotnej.

React 16.3 wprowadził trzecią opcję, która oferuję wygodę jak w przypadku referencji tekstowej, bez żadnych wad:

class MyComponent extends React.Component {
  constructor(props) {
    super(props);

    this.inputRef = React.createRef();
  }

  render() {
    return <input type="text" ref={this.inputRef} />;
  }

  componentDidMount() {
    this.inputRef.current.focus();
  }
}

Z uwagi na fakt, iż referencje obiektowe zostały dodane głównie jako zamiennik za referencje tekstowe, tryb rygorystyczny obecnie ostrzega w przypadku użyciu referencji tekstowych.

Uwaga:

Referencje w formie funkcji zwrotnej nadal będą wspierane wraz z nowym interfejsem createRef.

Nie musisz zamieniać referencji w postaci funkcji zwrotnej w swoich komponentach. Są one nieco bardziej elastyczne, więc pozostaną jako zaawansowana funkcjonalność.

Dowiedz się więcej o nowym API createRef tutaj.

Ostrzeganie o użyciu przestarzałego findDOMNode

React wspierał findDOMNode, aby umożliwić wyszukanie węzła powiązanego z daną instancją klasy w drzewie DOM. Zwykle jest to zbędna funkcjonalność, gdyż możesz podczepić referencję bezpośrednio do węzła DOM.

findDOMNode mógł również być używany na komponencie klasy, jednak powodowało to zakłócenie poziomów abstrakcji poprzez umożliwienie rodzicowi, aby wymagał wyrenderowania się pewnego potomka. Tworzyło to ryzyko podczas tzw. “refactoringu”, ponieważ nie można było zmienić implementacji komponentu, z węzłów którego mógłby korzystać rodzic. findDOMNode zawsze zwraca pierwsze dziecko, ale w przypadku użycia fragmentów jest możliwe, że komponent wyrenderuje wiele węzłów DOM. findDOMNode pozwala na jednorazowy odczyt, zwracając wynik tylko na żądanie. Jeżeli komponent potomny wyrenderuje inny węzeł, nie ma sposobu na obsłużenie tej zmiany. Innymi słowy findDOMNode działa wyłącznie gdy komponenty zwracają zawsze pojedynczy węzeł DOM, który nigdy się nie zmienia.

Zamiast tego do komponentu możesz jawnie przekazać referencję, którą następnie przekażesz do drzewa DOM przy użyciu przekierowania referencji.

Możesz również dodać do swojego komponentu opakowujący węzeł DOM i bezpośrednio do niego dowiązać referencję.

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.wrapper = React.createRef();
  }
  render() {
    return <div ref={this.wrapper}>{this.props.children}</div>;
  }
}

Uwaga:

W CSS możesz użyć atrybutu display: contents, jeżeli nie chcesz, aby węzeł nie był częścią szablonu.

Wykrywanie nieoczekiwanych efektów ubocznych

Zasadniczo, React działa w dwóch fazach:

  • Faza renderowania określa, jakie zmiany należy zaaplikować w np. drzewie DOM. Podczas tej fazy React wywołuje metodę render i porównuje jej wynik z poprzednim.
  • Faza aktualizacji następuje wtedy, gdy React aplikuje zmiany. (W przypadku React DOM następuje to, gdy React dodaje, aktualizuje i usuwa węzły DOM.) Podczas tej fazy React wywołuje również metody cyklu życia komponentu tj. componentDidMount czy componentDidUpdate.

Faza aktualizacji jest zazwyczaj bardzo szybka, jednak renderowanie może być powolne. Z tego powodu nadchodzący tryb asynchroniczny (który nie jest jeszcze domyślnie włączony), rozbija pracę związaną z renderowaniem na części, zatrzymując i wznawiając pracę, aby uniknąć blokowania przeglądarki. To oznacza, że React może wywołać metody cyklu życia w fazie renderowania więc niż raz przed aktualizacją lub może je wywołać nawet bez aktualizacji (z powodu błędu lub przerwania o większym priorytecie).

Cykl życia fazy renderowania odnosi się do poniższych metod z komponentu klasowego:

  • constructor
  • componentWillMount
  • componentWillReceiveProps
  • componentWillUpdate
  • getDerivedStateFromProps
  • shouldComponentUpdate
  • render
  • funkcje aktualizujące dla setState (pierwszy argument)

Ponieważ powyższe metody mogą być wywołane więcej niż raz, ważne jest, aby nie zawierały efektów ubocznych (ang side-effects). Zignorowanie tej zasady może prowadzić do różnych problemów, włączając w to wycieki pamięci i niepoprawny stan aplikacji. Niestety, może być ciężko wykryć problemy tego typu, ponieważ są one często niedeterministyczne.

Tryb rygorystyczny nie może automatycznie wykrywać efektów ubocznych, ale może pomóc w ich zauważeniu, poprzez sprawienie, by były trochę bardziej deterministyczne. Dzieje się to za sprawą celowego podwójnego wywoływania poniższych metod:

  • Metoda constructor komponentu klasowego
  • Metoda render
  • funkcja aktualizująca dla setState (pierwszy argument)
  • Statyczna metoda cyklu życia getDerivedStateFromProps

Uwaga:

Ma to zastosowanie tylko w trybie deweloperskim. Metody życia komponentu nie będą podwójnie wywoływane w trybie produkcyjnym.

Dla przykładu, rozważ poniższy kod:

class TopLevelRoute extends React.Component {
  constructor(props) {
    super(props);

    SharedApplicationState.recordEvent('ExampleComponent');
  }
}

Na pierwszy rzut oka kod nie wydaje się problematyczny. Ale jeżeli SharedApplicationState.recordEvent nie jest idempotentna, to stworzenie wielu instancji tego komponentu może prowadzić do niepoprawnego stanu aplikacji. Ten subtelny błąd może się nie ukazać podczas dewelopmentu lub może występować sporadycznie i zostać przeoczony.

Przez celowe podwójne wywołanie metod, takich jak konstruktor komponentu, tryb rygorystyczny sprawia, że wzorce tego typu są łatwiejsze do zauważenia.

Wykrywanie przestarzałego API kontekstów

Przestarzałe API kontekstów jest podatne na błędy i może zostać usunięte w przyszłych wersjach. Nadal będzie działać dla wszystkich wydań 16.x, ale w trybie rygorystycznym będzie w nich wyświetlany poniższy komunikat ostrzegawczy:

warn legacy context in strict mode

Przeczytaj dokumentację nowego API kontekstów, aby dowiedzieć się, jak zmigrować do nowej wersji.