React functional stateless component, PureComponent, Component; jakie są różnice i kiedy powinniśmy użyć czego?

Dowiedziałem się, że z React v15.3.0, mamy nową klasę bazową o nazwie PureComponent do rozszerzenia z PureRenderMixin wbudowaną. Rozumiem, że pod maską znajduje się płytkie porównanie rekwizytów wewnątrz shouldComponentUpdate.

Teraz mamy 3 sposoby definiowania komponentu Reactowego:

  1. funkcjonalny komponent bezstanowy, który nie rozszerza żadnej klasy
  2. komponent rozszerzający PureComponent klasę
  3. zwykły składnik, który rozszerza Component klasa
Jakiś czas temu nazywaliśmy bezstanowe komponenty czystymi komponentami, a nawet głupimi komponentami. Wygląda na to, że cała definicja słowa "czysty" zmieniła się w Reaccie.

Chociaż rozumiem podstawowe różnice między tymi trzema, nadal nie jestem pewien Kiedy wybrać co . Jakie są również skutki dla wydajności i kompromisy każdego z nich?


Update :

Oto pytanie, którego oczekuję objaśnienie:

  • Czy powinienem zdefiniować moje proste komponenty jako funkcjonalne (ze względu na prostotę) czy rozszerzyć PureComponent klasę (ze względu na wydajność)?
  • jest zwiększenie wydajności, że dostaję prawdziwy kompromis dla prostota, którą straciłem?
  • Czy kiedykolwiek będę musiał rozszerzyć normalną klasę Component, Kiedy zawsze będę mógł użyć PureComponent dla lepszej wydajności?
Author: free-soul, 2016-11-20

3 answers

Jak zdecydować, jak wybrać pomiędzy tymi trzema na podstawie przeznaczenia/wielkości/właściwości / zachowania naszych komponentów?

Rozszerzenie z React.PureComponent lub z React.Component metodą niestandardową shouldComponentUpdate ma wpływ na wydajność. Korzystanie z bezpaństwowych komponentów funkcjonalnych jest wyborem "architektonicznym" i nie ma żadnych korzyści z wydajności po wyjęciu z pudełka (jeszcze).

  • W przypadku prostych, prezentacyjnych komponentów, które muszą być łatwo ponownie użyte, preferują funkcjonalne bezstanowe komponenty. W ten sposób masz pewność, że są oddzielone od rzeczywistej logiki aplikacji,że są martwe-łatwe do przetestowania i że nie mają nieoczekiwanych skutków ubocznych. Wyjątkiem jest, jeśli z jakiegoś powodu masz dużo ich lub jeśli naprawdę potrzebujesz zoptymalizować ich metodę renderowania (ponieważ nie możesz zdefiniować shouldComponentUpdate dla bezstanowego komponentu funkcyjnego).

  • Extend PureComponent jeśli wiesz, że Twoje wyjście zależy od prostych właściwości/stanu ("simple" oznacza brak zagnieżdżonych struktur danych, jak PureComponent wykonuje płytkie porównanie) i potrzebujesz / możesz uzyskać pewne ulepszenia wydajności.

  • Rozszerz Component i zaimplementuj własne shouldComponentUpdate jeśli potrzebujesz poprawy wydajności, wykonując niestandardową logikę porównywania pomiędzy kolejnymi / bieżącymi właściwościami i stanem. Na przykład, można szybko wykonać głębokie porównanie za pomocą lodash # isEqual:

    class MyComponent extends Component {
        shouldComponentUpdate (nextProps, nextState) {
            return !_.isEqual(this.props, nextProps) || !_.isEqual(this.state, nextState);
        }
    }
    

Również implementacja własnego shouldComponentUpdate lub rozszerzenie z PureComponent to optymalizacje i jak zwykle powinieneś zacząć szukać do tego tylko wtedy, gdy masz problemy z wydajnością (unikaj przedwczesnych optymalizacji ). Z reguły zawsze staram się wykonywać te optymalizacje, gdy aplikacja jest w stanie roboczym, z większością funkcji już zaimplementowanych. O wiele łatwiej jest skupić się na problemach z wydajnością, gdy faktycznie wchodzą w drogę.

Więcej szczegółów

Funkcjonalne komponenty bezpaństwowe:

Są one definiowane tylko za pomocą funkcji. Ponieważ nie ma stanu wewnętrznego dla komponentu bezstanowego, wyjście (to, co jest renderowane) zależy tylko od właściwości podanych jako Wejście dla tej funkcji.

Plusy:

  • Najprostszy możliwy sposób definiowania komponentu w Reaccie. Jeśli nie musisz zarządzać żadnym stanem, po co przejmować się klasami i dziedziczeniem? Jedną z głównych różnic między funkcją a klasą jest to, że dzięki funkcji masz pewność, że wyjście zależy tylko od wejścia (nie od żadnej historii poprzedniego egzekucje).

  • Najlepiej w aplikacji powinieneś dążyć do posiadania jak największej liczby bezpaństwowych komponentów, ponieważ zwykle oznacza to, że przeniosłeś swoją logikę poza warstwę widoku i przeniosłeś ją do czegoś takiego jak redux, co oznacza, że możesz przetestować swoją prawdziwą logikę bez konieczności renderowania czegokolwiek (znacznie łatwiejsze do przetestowania, bardziej wielokrotnego użytku itp.).

Wady:

  • Brak metod cyklu życia. Nie masz sposobu na zdefiniowanie componentDidMount i innych przyjaciół. Zwykle robisz to w komponencie nadrzędnym wyżej w hierarchii, dzięki czemu możesz zamienić wszystkie dzieci w bezpaństwowe.

  • Nie można ręcznie kontrolować, kiedy potrzebne jest ponowne renderowanie, ponieważ nie można zdefiniować shouldComponentUpdate. Ponowne renderowanie odbywa się za każdym razem, gdy komponent otrzymuje nowe właściwości (nie ma mowy o płytkim porównaniu, itp.). W przyszłości React może automatycznie optymalizować komponenty bezstanowe, na razie istnieje kilka bibliotek, z których możesz korzystać. Ponieważ bezstanowe komponenty są tylko funkcjami, zasadniczo jest to klasyczny problem "memoizacji funkcji".

  • Refs nie są obsługiwane: https://github.com/facebook/react/issues/4936

Komponent, który rozszerza klasę PureComponent VS zwykły komponent, który rozszerza klasę komponentu:

React posiadał PureRenderMixin, którą można było dołączyć do klasy zdefiniowanej za pomocą składni React.createClass. Mixin po prostu zdefiniowałby shouldComponentUpdate dokonując płytkiego porównania pomiędzy kolejnymi rekwizytami i Następny stan, aby sprawdzić, czy coś tam się zmieniło. Jeśli nic się nie zmieni, nie ma potrzeby ponownego renderowania.

Jeśli chcesz używać składni ES6, nie możesz używać mixinów. Dla wygody React wprowadził klasę PureComponent, z której można dziedziczyć zamiast Component. PureComponent po prostu implementuje shouldComponentUpdate w taki sam sposób jak PureRendererMixin. Jest to głównie wygoda, więc nie musisz go wdrażać samodzielnie, ponieważ płytkie porównanie aktualnego / następnego stanu i rekwizytów jest prawdopodobnie najbardziej wspólny scenariusz, który może dać ci kilka szybkich wyników wygrywa.

Przykład:

class UserAvatar extends Component {
    render() {
       return <div><img src={this.props.imageUrl} /> {{ this.props.username }} </div>
    }
} 

Jak widać wyjście zależy od props.imageUrl i props.username. Jeśli w komponencie nadrzędnym renderujesz <UserAvatar username="fabio" imageUrl="http://foo.com/fabio.jpg" /> z tymi samymi właściwościami, React wywoła render za każdym razem, nawet jeśli wynik byłby dokładnie taki sam. Pamiętaj jednak, że React implementuje różnice dom, więc DOM nie będzie faktycznie aktualizowany. Mimo to wykonywanie różnic dom może być kosztowne, więc w tym scenariuszu byłoby to marnotrawstwo.

Jeśli UserAvatar składowa rozszerza PureComponent zamiast tego, wykonywane jest płytkie porównanie. A ponieważ rekwizyty i następne krople są takie same, {26]} w ogóle nie będą wywoływane.

Uwagi na temat definicji "czystego" w Reaccie:

Ogólnie rzecz biorąc, "czysta funkcja" jest funkcją, która zawsze ocenia ten sam wynik, biorąc pod uwagę te same dane wejściowe. Wyjście (w przypadku Reacta, to jest zwracane przez metodę render) nie zależy od historii/stanu i nie ma żadnych efekty uboczne (operacje, które zmieniają" świat " poza funkcją).

W Reaccie, komponenty bezstanowe niekoniecznie są czystymi komponentami zgodnie z powyższą definicją, jeśli" bezstanowy " komponent, który nigdy nie wywołuje this.setState i który nie używa this.state.

W rzeczywistości, w PureComponent, nadal można wykonywać efekty uboczne podczas metod cyklu życia. Na przykład można wysłać żądanie ajax wewnątrz componentDidMount lub można wykonać pewne obliczenia DOM dynamicznie dostosować wysokość div w obrębie render.

Definicja "Dumb components" ma bardziej "praktyczne" znaczenie (przynajmniej w moim rozumieniu): głupi komponent "otrzymuje" polecenie, co ma robić przez komponent macierzysty za pomocą właściwości i nie wie, jak to zrobić, ale zamiast tego używa wywołań zwrotnych właściwości.

Przykład "inteligentnego" AvatarComponent:

class AvatarComponent extends Component {
    expandAvatar () {
        this.setState({ loading: true });
        sendAjaxRequest(...).then(() => {
            this.setState({ loading: false });
        });
    }        

    render () {
        <div onClick={this.expandAvatar}>
            <img src={this.props.username} />
        </div>
    }
}

Przykład "głupiego" AvatarComponent:

class AvatarComponent extends Component {
    render () {
        <div onClick={this.props.onExpandAvatar}>
            {this.props.loading && <div className="spinner" />}
            <img src={this.props.username} />
        </div>
    }
}

Na koniec powiedziałbym, że "głupi", "bezpaństwowiec" i "czysty" to zupełnie różne pojęcia, które czasami mogą nakładanie się, ale niekoniecznie, w zależności głównie od przypadku użycia.

 240
Author: fabio.sussetto,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-28 19:29:16

Nie jestem geniuszem w stosunku do Reacta, ale z mojego zrozumienia możemy używać każdego komponentu w następujących sytuacjach

  1. Komponent Bezstanowy -- są to komponenty, które nie mają cyklu życia, więc te komponenty powinny być używane do renderowania powtarzającego się elementu komponentu nadrzędnego, takiego jak renderowanie listy tekstowej, która po prostu wyświetla informacje i nie ma żadnych akcji do wykonania.

  2. Pure component -- są to elementy, które mają cyklu życia i zawsze zwrócą ten sam wynik, gdy podany zostanie określony zestaw rekwizytów. Komponenty te mogą być używane podczas wyświetlania listy wyników lub konkretnych danych obiektu, które nie mają złożonych elementów potomnych i są używane do wykonywania operacji, które wpływają tylko na siebie. takie Wyświetlanie listy kart użytkownika lub listy kart produktów (podstawowe informacje o produkcie) i tylko działanie może wykonać użytkownik jest Kliknij, aby wyświetlić stronę szczegółów lub Dodaj do koszyka.

  3. Normalne składniki lub złożone Components -- użyłem terminu complex component, ponieważ są to zazwyczaj komponenty poziomu strony i składają się z wielu komponentów potomnych, a ponieważ każdy z nich może zachowywać się w swój własny, unikalny sposób, więc nie możesz być w 100% pewien, że będzie renderował ten sam wynik w danym stanie. Jak mówiłem, zazwyczaj powinny być one używane jako komponenty kontenera

 19
Author: abhirathore2006,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-14 18:28:15

Oto moje spojrzenie na PureComponent i Kiedy powinieneś go używać (a kiedy nie powinieneś): Czym jest React.PureComponent i kiedy go używać

 -1
Author: Sergey Stadnik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-24 23:43:37