Metody cyklu życia komponentu w React.js

Ten wpis jest 10 częścią z 41 w kursie React.js
wp-content/uploads/2017/10/React_logo_wordmark-300x101-1-e1508612391308.png
  1. React.js: Wprowadzenie do kursu od podstaw
  2. Poznaj React.js
  3. Pierwszy komponent w React.js
  4. Props czyli atrybuty w React.js
  5. Podział na komponenty w React.js
  6. Klasy jako komponenty React.js
  7. Interakcja z komponentami React.js
  8. Stan komponentów React.js
  9. State w React.js 2
  10. Metody cyklu życia komponentu w React.js
  11. React.js w przykładach: filtrowanie statycznej listy
  12. Tworzenie aplikacji React.js dzięki create-react-app
  13. React.js na GitHub Pages dzięki create-react-app
  14. Testowanie aplikacji React.js — podstawy Enzyme
  15. Testowanie React.js w Enzyme — props, state i interakcje
  16. Poprawne bindowanie funkcji w React.js
  17. Odpowiadam na pytania: Babel, ECMAScript, destrukturyzacja, onClick, className
  18. Komunikacja pomiędzy komponentami w React.js
  19. Komunikacja z API w React.js
  20. Formularze w React.js — kontrolowane komponenty
  21. Formularze w React.js — niekontrolowane komponenty
  22. Odpowiadam na pytania: props, nawiasy klamrowe, funkcje vs klasy, import react
  23. TDD w React.js z pomocą react-testing-library
  24. Flux i Redux: globalny store i jednokierunkowy przepływ danych
  25. React + Redux — kurs: wprowadzenie i podstawy
  26. React + Redux — filtrowanie listy, proste selektory
  27. Projektowanie komponentów: Presentational & Container Components
  28. Asynchroniczność w Redux: redux-thunk
  29. Kiedy używać state, a kiedy Redux?
  30. Nowe metody cyklu życia: getDerivedStateFromProps i getSnapshotBeforeUpdate
  31. Leniwe ładowanie komponentów w React dzięki import
  32. Higher Order Reducers — Redux i powtarzanie kodu
  33. React Hooks — wprowadzenie i motywacja
  34. React Hooks: useState, czyli stan w komponentach funkcyjnych
  35. React Hooks: useState — wiele stanów, callbacki i inne niuanse
  36. React Hooks: useEffect — efekty uboczne w komponencie
  37. React Hooks a żądania do API
  38. useReducer — przenoszenie logiki poza komponent
  39. useMemo, useCallback, czyli rozwiązanie problemów ze zmieniającymi się propsami
  40. Wady React Hooks
  41. React Hooks: Piszemy własne hooki!

Przy okazji omawiania komponentów będących klasami w React.js, wspomniałem też o możliwości korzystania z metod cyklu życia (lifecycle methods). Chciałbym do tego tematu teraz powrócić. Pokażę jakie metody cyklu życia definiuje React.js, do czego one służą i kiedy mogą się przydać.

Cykl życia komponentu

Bardzo dokładnie omawiamy cykl życia komponentów na szkoleniach. Naucz się React na szkoleniu z Type of Web!

Każdy komponent ma pewien określony cykl życia. Na odpowiednich etapach wywoływane są też jego metody cyklu życia. Możemy je podzielić ogólnie na dwie grupy:

  • z nazwami zaczynającymi się od will — wywoływane zanim się coś wydarzy
  • z nazwami zaczynającymi się od did — wywoływane po tym jak coś się zdarzyło

Oto kolejne etapy życia komponentów:

Montowanie

Komponent jest tworzony i dodawany do drzewa Dom.

  • constructor(props) — jeśli definiujesz konstruktor to nie zapomnij wywołać w nim super(props) na samym początku; możesz też tam ustawić this.state = {…} bez konieczności używania setState. To będzie początkowy stan aplikacji. Inne operacje (efekty uboczne, subskrypcje) powinny się znaleźć w componentDidMount
  • componentWillMount() — wywoływany tuż przed zamontowaniem komponentu; ta metoda raczej Ci się nie przyda
  • render() — funkcja, która powinna zwrócić jeden z możliwych wyników:
    • element (JSX)
    • tablicę elementów (JSX)
    • string lub liczbę
    • null (nic się nie renderuje)
    • boolean (nic się nie renderuje)
    • Portal (stworzony przez ReactDOM.createPortal(…))
  • componentDidMount() — wywoływana po zamontowaniu komponentu; to dobre miejsce na jakiekolwiek funkcje polegające na DOM lub na subskrypcje (nie zapomnij o usunięciu subskrypcji w componentWillUnmount()!)

Aktualizacja

Update może zostać wywołany gdy zmieniają się props lub state.

  • componentWillReceiveProps(nextProps) — wywoływana m.in. gdy zmieniają się propsy (np. gdy element-rodzic je zmienia); warto porównać this.props z nextProps i sprawdzić czy rzeczywiście coś się zmieniło (bo nie zawsze musi…)
  • shouldComponentUpdate(nextProps, nextState) — wywoływana zawsze przed render(); jeśli z tej funkcji zwrócisz false to render() nie zostanie wykonany, a widok się raczej nie przerenderuje — można to wykorzystać do optymalizowania aplikacji; UWAGA: komponenty-dzieci nadal mogą się przerenderować np. gdy zmieni się ich state, a w przyszłości React będzie traktował funkcję  shouldComponentUpdate() tylko jako wskazówkę, a nie wyznacznik — wrócę do tego tematu jeszcze
  • componentWillUpdate(nextProps, nextState) — wywoływana tuż przed render() — pamiętaj aby nie modyfikować state wewnątrz tej funkcji
  • render() — j.w.
  • componentDidUpdate(prevProps, prevState) — wywoływana od razu po renderze; dobre miejsce na zmiany w DOM (jeśli takowe są potrzebne)

Odmontowanie

Wywoływane gdy komponent jest usuwany z DOM

  • componentWillUnmount() — wywoływana przed usunięciem komponentu z DOM; dobre miejsce na „posprzątanie” po sobie — usunięcie timerów, subskrypcji, zmian w DOM itd.

Łapanie błędów

  • componentDidCatch(error, info) — wywoływana gdy pojawi się błąd w czasie renderowania, wywoływania metod cyklu życia lub w konstruktorze — zagnieżdżonych komponentów; błędy w samym komponencie nie są tutaj łapane (zostaną złapane w komponencie-rodzicu)

Przykład

Oto prosta aplikacja, która pokazuje ważny przykład używania metod cyklu życia. Są to dwa komponenty, App odpowiada za pokazywanie i ukrywanie (po kliknięciu w przycisk) drugiego komponentu. Drugi komponent to Date, który co sekundę aktualizuje stan i wyświetla aktualną datę i godzinę. Wykorzystane zostały takie lifecycle methods:

  • constructor() — ustawianie początkowego stanu
  • componentDidMount() — rozpoczęcie odliczania (setInterval)
  • componentWillUnmount() — usunięcie odliczania (clearInterval)

Warto też zwrócić uwagę na sposób w jaki komponent App renderuje komponent Date w zależności od this.state.dateVisible:

<div>
  {this.state.dateVisible && <DateComponent />}
</div>

See the Pen Metody cyklu życia komponentu w React.js by Michał Miszczyszyn (@mmiszy) on CodePen.

Jeśli chcesz na bieżąco śledzić kolejne części kursu React.js to koniecznie polub mnie na Facebooku i zapisz się na newsletter.

Nie wysyłamy spamu, tylko wartościowe informacje. W każdej chwili możesz się wypisać klikając „wypisz się” w stopce maila.

Ćwiczenie

Ćwiczenie: Stwórz dwa komponenty (rodzic i dziecko). Oto wymagania:

  1. Rodzic pozwala na ustawienie (input + button + onClick+ setState) jakiejś wartości liczbowej i przekazuje ją do dziecka jako props.
  2. Dziecko ma początkowo wyświetlać liczbę podaną od rodzica, a dodatkowo ma umożliwiać zwiększanie i zmniejszanie tej liczby (button + onClick + setState).
  3. W momencie gdy rodzic ustawi liczbę, dziecko powinno zresetować swój stan do podanej liczby (componentWillReceiveProps).

Aktualizacja 11.02.2019 r.: Przekreśliłem zadania powyżej. Miały one wyłącznie charakter dydaktyczny w celu poznania metody cyklu życia componentWillReceiveProps, ale wiele osób bardzo je sobie zapamiętało i stosowało podobny wzorzec w swoich aplikacjach. Poza tym React oznaczył tę metodę jako przestarzałą i niezalecaną. Zajrzyj do tego wpisu:

Nowe metody cyklu życia: getDerivedStateFromProps i getSnapshotBeforeUpdate

Sugerowane tutaj przeze mnie rozwiązanie było błędne. Prawidłowym rozwiązaniem problemu powyżej jest przeniesienie stanu dziecka wyżej — do rodzica (tzw. lifting state up). W ten sposób rodzic kontroluje stan obu inputów, a dziecko informuje go o zmianach, które chce wprowadzić. Dzięki temu unika się kilku częstych problemów: z rerenderem (który mógłby prowadzić do skasowania się wartości z inputów), z koniecznością wykrywania zmian (przez niezalecany componentWillReceiveProps), czy choćby z niejasnym przepływem danych (dane do dziecka od rodzica spływają w dół, ale tylko czasem… a dziecko nigdy nie informuje rodzica o zmianach — to niedobrze!). Oto zaktualizowana treść ćwiczenia:

Zaktualizowane ćwiczenie

Ćwiczenie: Stwórz dwa komponenty (rodzic i dziecko). Oto wymagania:

  1. Rodzic pozwala na ustawienie w inpucie jakiejś wartości liczbowej i przekazuje ją do dziecka.
  2. Dziecko ma początkowo wyświetlać liczbę podaną od rodzica, a dodatkowo ma umożliwiać zwiększanie i zmniejszanie tej liczby.
  3. W momencie, gdy rodzic ustawi liczbę, dziecko powinno zresetować swój stan do podanej liczby.
  4. Podpowiedź: Zastosuj tutaj lifting state up i stan obu komponentów trzymaj w rodzicu.

Napisz w komentarzu czy się udało. A jeśli masz jakieś wątpliwości albo nawet nie wiesz jak zacząć — odezwij się! Pomogę!

Nawigacja po kursie:
  1. React.js: Wprowadzenie do kursu od podstaw
  2. Poznaj React.js
  3. Pierwszy komponent w React.js
  4. Props czyli atrybuty w React.js
  5. Podział na komponenty w React.js
  6. Klasy jako komponenty React.js
  7. Interakcja z komponentami React.js
  8. Stan komponentów React.js
  9. State w React.js 2
  10. Metody cyklu życia komponentu w React.js
  11. React.js w przykładach: filtrowanie statycznej listy
  12. Tworzenie aplikacji React.js dzięki create-react-app
  13. React.js na GitHub Pages dzięki create-react-app
  14. Testowanie aplikacji React.js — podstawy Enzyme
  15. Testowanie React.js w Enzyme — props, state i interakcje
  16. Poprawne bindowanie funkcji w React.js
  17. Odpowiadam na pytania: Babel, ECMAScript, destrukturyzacja, onClick, className
  18. Komunikacja pomiędzy komponentami w React.js
  19. Komunikacja z API w React.js
  20. Formularze w React.js — kontrolowane komponenty
  21. Formularze w React.js — niekontrolowane komponenty
  22. Odpowiadam na pytania: props, nawiasy klamrowe, funkcje vs klasy, import react
  23. TDD w React.js z pomocą react-testing-library
  24. Flux i Redux: globalny store i jednokierunkowy przepływ danych
  25. React + Redux — kurs: wprowadzenie i podstawy
  26. React + Redux — filtrowanie listy, proste selektory
  27. Projektowanie komponentów: Presentational & Container Components
  28. Asynchroniczność w Redux: redux-thunk
  29. Kiedy używać state, a kiedy Redux?
  30. Nowe metody cyklu życia: getDerivedStateFromProps i getSnapshotBeforeUpdate
  31. Leniwe ładowanie komponentów w React dzięki import
  32. Higher Order Reducers — Redux i powtarzanie kodu
  33. React Hooks — wprowadzenie i motywacja
  34. React Hooks: useState, czyli stan w komponentach funkcyjnych
  35. React Hooks: useState — wiele stanów, callbacki i inne niuanse
  36. React Hooks: useEffect — efekty uboczne w komponencie
  37. React Hooks a żądania do API
  38. useReducer — przenoszenie logiki poza komponent
  39. useMemo, useCallback, czyli rozwiązanie problemów ze zmieniającymi się propsami
  40. Wady React Hooks
  41. React Hooks: Piszemy własne hooki!

Nie wysyłamy spamu, tylko wartościowe informacje. W każdej chwili możesz się wypisać klikając „wypisz się” w stopce maila.

Subscribe
Powiadom o
guest
75 komentarzy
Most Voted
Newest Oldest
Inline Feedbacks
View all comments
Michał
Michał
2 lat temu

Poniżej rozwiązanie do ćwiczenia:

https://pastebin.com/BtTwq70t

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

    this.state = {
      input: null,
      forwardValue: null
    }

    this.handleClick = this.handleClick.bind(this);
    this.handleChange = this.handleChange.bind(this);
  }

  handleChange(event) {
    this.setState({ input: event.target.value });
  }

  handleClick() {
    this.setState({ forwardValue: this.state.input });
  }

  render() {
    return(
      
{this.state.forwardValue && }
); } } class Child extends React.Component { constructor(props) { super(props); this.state = { fromParent: Number(props.value), current: Number(props.value), } this.handleIncrement = this.handleIncrement.bind(this); this.handleDecrement = this.handleDecrement.bind(this); } componentWillReceiveProps(nextProps) { if (nextProps.value != this.state.fromParent) { this.setState({ fromParent: Number(nextProps.value), current: Number(nextProps.value), }) } } handleIncrement() { this.setState({ current: this.state.current + 1 }) } handleDecrement() { this.setState({ current: this.state.current - 1 }) } render() { return(
); } } ReactDOM.render( , document.getElementById('root') );

Patrycja Bąk
Patrycja Bąk
10 miesięcy temu
Reply to  Michał

Mały refaktor dla potomnych:
Niestety sama nie wpadłam na rozwiązanie ale przepisywanie kodu dla zrozumienia tez uczy 🙂
class Parent extends React.Component {
constructor(props) {
super(props);

this.state = {
input: null,
forwardValue: null
}

this.handleClick = this.handleClick.bind(this);
this.handleChange = this.handleChange.bind(this);
}

handleChange(event) {
this.setState({ input: event.target.value });
}

handleClick() {
this.setState({ forwardValue: this.state.input });
}

render() {
return(

Propagate to child
{this.state.forwardValue && }

);
}
}

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

this.state = {
fromParent: Number(props.value),
current: Number(props.value)
}

this.handleIncrement = this.handleIncrement.bind(this);
this.handleDecrement = this.handleDecrement.bind(this);
}

componentWillReceiveProps(nextProps) {
if (nextProps.value != this.state.fromParent) {
this.setState({
fromParent: Number(nextProps.value),
current: Number(nextProps.value),
})
}
}

handleIncrement() {
this.setState({ current: this.state.current + 1 })
}

handleDecrement() {
this.setState({ current: this.state.current – 1 })
}

render() {
return(

{this.state.current}
+

);
}
}

ReactDOM.render(
,
document.getElementById(‚root’)
);

Patrycja Bąk
Patrycja Bąk
10 miesięcy temu
Reply to  Michał

Ten kod już nie działa, wywala masę błędów 🙂

Agata
Agata
1 rok temu
Reply to  Michał

Cześć,
Mam dwa pytanie dotyczące powyższego kodu.
Pierwsze dotyczy tego fragmentu z komponentu Child:

componentWillReceiveProps(nextProps) {
if (nextProps.value != this.state.fromParent) {

Co jest tu przekazywane jako ‚nextProps’?

Drugie pytanie dotyczy tego fragmentu:
{this.state.forwardValue && }
Czym różni się zapis:
{}

Kurs świetny 🙂
Pozdrowienia,
Agata

One_92tb
One_92tb
1 rok temu
Reply to  Michał

componentWillReceiveProps(nextProps) {
if (nextProps.value != this.state.fromParent) {
this.setState({
fromParent: Number(nextProps.value),
current: Number(nextProps.value),
})
}
}

Dlaczego tutaj mamy instrukcje warunkową?

Paulina
Paulina
2 lat temu

Czy mogłabym poprosić o wytłumaczenie fragmentów kodu ? Staram się zrozumieć całość ale w tych miejscach mam problem, nie chcę iść dalej bo będę miała braki . Jestem początkująca i staram się zrozumieć podstawy.
Pytanie : co się kryje pod „Number(props.value)” i dlaczego tak sie to pisze, oraz jesli chodzi o drugi fragment dlaczego akurat nextProps i skąd funkcja wie czym ona jest skoro nigdzie wczesniej tego nie ma. Poźniej rozumiem, iż porównuje sie wartości.
this.state = {
fromParent: Number(props.value),
current: Number(props.value),
}

componentWillReceiveProps(nextProps) {
if (nextProps.value != this.state.fromParent) {
this.setState({
fromParent: Number(nextProps.value),
current: Number(nextProps.value),
})
}

Paulina
Paulina
2 lat temu

Dzięki!

Paulina
Paulina
2 lat temu

Tak, myślę że tak 🙂

anja sudol
anja sudol
1 rok temu

Hej, a dlaczego nie ma Number(this.props.input) ? Czy takie oznaczenie
this.state = {
fromParent: Number(props.value),
current: Number(props.value),
}
Powoduje, że Kopiowane są wszytskie proppsy poprzednie i najnowsze ?

anja sudol
anja sudol
2 lat temu

Dziękuję, chodziło mi oczywiście o Number(props.value)

Kamil
Kamil
2 lat temu

Cześć. Nie rozumiem za bardzo, dlaczego stosuje się constructor. Widziałem przykłady, gdzie ustawiano stan początkowy bez constructora. Od czego zależy jego użycie?

A sam kurs bardzo fajny:)

Kamil
Kamil
2 lat temu

No i wszystko jasne, dzięki:)

Mateusz
Mateusz
2 lat temu

Cześć, czy mógłby ktoś wytłumaczyć czym jest subskrypcja w React? Może być na jakimś przykładzie. Z góry dzięki 🙂

Wojciech Niedźwiedź
Wojciech Niedźwiedź
2 lat temu

Dlaczego w przykładzie z pokazywaniem daty w komponencie DateComponent w metodzie render() dla zmiennej dateStr sprawdzamy najpierw czy zmienna this.state.date istnieje? Przecież przy utworzeniu obiektu w konstruktorze zostaje ona zdefiniowana.

trackback

[…] Metody cyklu życia komponentu w React.js ·  28 May 2018 […]

crisu
crisu
1 rok temu

Ktoś wie czemu w przykładzie musimy użyć tego bindowania ?
window.setInterval(this.updateDate.bind(this), 1000);

Damian B
Damian B
1 rok temu

Michał,
Kawał dobrej roboty przy tworzeniu tego kursu – zaciekawiłeś mnie i lekcja po lekcji dotarłem do tego miejsca, a mam nadzieję przedostać się do samego końca.

Moja odrobiona praca domowa: https://codepen.io/anon/pen/gdZqdR

Kamil Mirosz
Kamil Mirosz
1 rok temu

Moja wersja zadania z przykładu 🙂
https://jsbin.com/yaviqitute/edit?html,output

Starałem się napisać to samemu ale wspomagałem się podglądem kodu z przykładu co do użycia nowych funkcji 🙂

Mega Kurs ! 🙂

Rotarepmi
Rotarepmi
1 rok temu

https://codepen.io/Rotarepmi/pen/vrNaEO

Moje podwójne rozwiązanie, także z użyciem getDerrivedStateFromProps 🙂

Rafał Staśkiewicz
Rafał Staśkiewicz
1 rok temu

Chciałbym zapytać, kiedy używać wspomnianej w poprzednim wpisie updater function, a kiedy przekazywać do setState() obiekt z wartościami, które chcemy zaktualizować.
Do tej port zauważyłem trzy różne typy sytuacji:

1) Updater:
https://pastebin.com/GEBCsjmF

2) Updater:
https://pastebin.com/3MC9vATf
3) I tutaj mam problem, bo chciałbym wykorzystać event, analogicznie jak wyżej ale rzuca mi nulla:
https://pastebin.com/hqa3t2ax

Joanna Trapp
Joanna Trapp
1 rok temu

PRAWIE się udało Mój kod:
class App extends React.Component {
constructor(props) {
super(props);
this.state = { input: 0, number: 0};
}
onInputChange(e) {
this.setState({input: Number(e.target.value)});
}
onButtonClick() {
this.setState({number: this.state.input});
}
render() {
return (



);
}
}

class ChildComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
childNumber: Number(props.number)
};
}
componentWillReceiveProps(newProps){
this.setState({childNumber: newProps.parentNumber});
}
increase(){
this.setState({childNumber: this.state.childNumber + 1});
}
decrease(){
this.setState({childNumber: this.state.childNumber - 1});
}
render() {
return (

{this.state.childNumber}

)
}
}
ReactDOM.render(, document.getElementById("app"));

Nie wiem tylko, dlaczego przy zmienianiu liczby w inpucie od razu zmienia mi liczbę w outpucie na taką, jak była ostawiona wcześniej…. :/

greg
greg
1 rok temu

Poniżej moje rozwiązanie, korzystam z pluginu do babelu, który rozszerza właściwości klas, dlatego składnia może się różnić od składni podanej przez innych 🙂

import React from ‚react’;

class BtwComponentApp extends React.Component {

state = {
number: 0,
numberPassed: 0
};

onInputChange = (e) => {
const inputChangeVariable = parseInt(e.target.value);
this.setState({
number: inputChangeVariable
});
};

passParent = () => {
this.setState({
numberPassed: this.state.number
})
};

render() {
return (



);
}
}

class BtwChild extends React.Component {

state = {
childNum: 0
};

increaseNumber =() => {
this.setState((prevState) => ({
childNum: prevState.childNum+1
}))
};

componentDidUpdate() {
console.log(‚will’);
}

componentWillReceiveProps(nextProps) {
if(this.props.num !== nextProps.num) {
this.setState({
childNum: nextProps.num
})
}
}

render() {
return (

This is number from a props

{this.props.numberPassed}

This is number from local state!

{this.state.childNum}

);
}
}

export {BtwComponentApp};

Agnieszka Sołtysik
Agnieszka Sołtysik
1 rok temu

Poniżej moje rozwiązanie. Będę wdzięczna za wszelkie uwagi i wskazówki

class App extends React.Component {

constructor() {

super()

this.state = {

input: 0,

number: 0

}

}

sendToChild() {

this.setState({

number: this.state.input

})

}

onChangedInput(event) {

this.setState({

input: Number(event.target.value)

})

}

render() {

return (

)

}

}

class SmallCounter extends React.Component {

constructor() {

super()

this.state = {

counter: 0

}

}

componentWillReceiveProps(nextProps) {

this.setState({

counter: nextProps.counter,

})

}

increment() {

this.setState({

counter: this.state.counter + 1,

})

}

decrement() {

this.setState({

counter: this.state.counter – 1,

})

}

render() {

return (

{this.state.counter}

)

}

}

Jurko
Jurko
1 rok temu

Akurat robiłem ćwiczenie XD

Jurko
Jurko
1 rok temu

Długo kminiłem, ale React Tutorial pomógł
https://reactjs.org/docs/lifting-state-up.html

Jurko
Jurko
1 rok temu
Jurko
Jurko
1 rok temu

Jurko
Jurko
1 rok temu

Rozwiązanie dla aktualnego ćwiczenia:

https://pastebin.com/1ujwR51X

Rafal
Rafal
1 rok temu

Czy może mi ktoś wyjaśnić dlaczego to nie działa?: Chodzi o cudzyslowy oraz bind(this)

{this.state.forwardValue && }

tylko to:



{this.state.forwardValue && }

Rafal
Rafal
1 rok temu

czy może mi ktoś wyjaśnić dlaczego to nie działa: ?

oczywiscie jest wyzej , testowalem przyklad z przykladow podanych przez uzytkownikow blogoa ponizej w kom.:

this.handleClick = this.handleClick.bind(this);
this.handleChange = this.handleChange.bind(this);

{this.state.forwardValue && }

tylko to bez cudzyslowow i z bind.this? gubie sie jaka forma jest poprawna, bo przyklady podaja ludzie ze dziala a u mnie niestety

{this.state.forwardValue && }

Dragan
Dragan
1 rok temu

Cześć – po aktualizacji ćwiczeń fajnie było by wyjaśnić w kilku słowach o co chodzi z getDerivedStateFromProps i jaka jest różnica między nim a componentDidUpdate. Chwile mi zajęło, zanim zobaczyłem różnicę 🙂 Dodatkowo nie jestem pewny jednej rzeczy. Jeżeli komponent dziecka może mieć swój stan, którego inicjalna wartość jest ustawiana przez props i aktualizacja miała by się odbywać przez getDerivedStateFromProps jak rozróżnić że props się tak naprawdę zmienił jeżeli 2 razy z rzędu ustawiany jest ten sam props?

Przykład: https://stackblitz.com/edit/typeofweb-lesson10

Kliknięcie na guzik „set” zmienia prop dziecka, które dzięki getDerivedStateFromProps zmienia swój stan. Jednak gdy guzikami „+” i „-” zmienię stan dziecka i kliknę jeszcze raz „set” bez miany wartości inputa, oczekiwał bym, że stan dziecka się zaktualizuje, a nie dzieje się tak, bo defakto wartość prop.value się nie zmieniła.

Jak coś takiego ugrać?

Dragan
Dragan
1 rok temu
Reply to  Dragan

https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html – to rozwiązało mój problem – ref lub key 🙂

Dragan
Dragan
1 rok temu

Dzięki, ale wydaje mi się że już wiem o co chodzi 🙂 Dokładniejsze przestudiowanie cyklu życia komponentu dużo wyjaśniło (świetny diagram –comment image) . Wiem, że w zadaniu chodziło lifting state up, ale ciekawiło mnie dlaczego wycofali się ze starej metody 🙂

Slawko
Slawko
1 rok temu

Dobry kursik. Dobre zadanko . Wymyśliłem takie coś ;>
https://pastebin.com/Q9yMTmXp
Pozdro!

Łukasz Parysek
Łukasz Parysek
1 rok temu

Z użyciem lifting state up:

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

this.state = { number: 5 };
this.handleNumberChange = this.handleNumberChange.bind(this);
}

handleNumberChange(number) {
this.setState(() => {
return { number }
})
}

render() {
return (

);
}
}

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

this.handleChange = this.handleChange.bind(this);
}

handleChange(e) {
const { onNumberChange } = this.props;
onNumberChange(e.target.value);
}

render() {
const { number } = this.props;
return (
Lifting state up

)
}
}

Bartek
Bartek
2 lat temu

Czy mój komentarz został usunięty?

Bartek
Bartek
2 lat temu

Jest problem z typem, gdy wpisuje liczbę do inputa to Child interpretuje tego propsa jako String’a i zamiast inkrementować konkatenuję.. Próbowałem PropTypes lecz CodePen chyba tego nie obsługuje, czy jest na to jakiś inny sposób?

Moje rozwiązanie:

class Parent extends React.Component {
constructor(props) {
super(props);
this.state = { value: 0,
showChild : true};
}

_onChange(e) {
this.setState({ value: e.target.value});
}

_toggleChild(){
this.setState(state => ({ showChild: !this.state.showChild}));
}

render() {
return (


{this.state.showChild && };

);
}
}

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

this.state = {
value: this.props.value,
};
}

componentWillReceiveProps(nextProps){
this.setState(state => ({
value : nextProps.value,
}));
}

_incrementChild(){
this.setState(state => ({
value : this.state.value + 1,
}));
}

_decrementChild(){
this.setState(state => ({
value : this.state.value – 1,
}));
}

render() {
return

{this.state.value}


;
}
}

ReactDOM.render(, document.getElementById(„app”));

Krzysztof Dziekiewicz
Krzysztof Dziekiewicz
9 miesięcy temu

>
class ParentComponent extends React.Component {
constructor(props) {
super(props);
this.state = {value: 0, forward: 0};
this.changeValue = this.changeValue.bind(this);
this.onButtonClicked = this.onButtonClicked.bind(this);
}

changeValue(event) {
const value = event.target.value;
this.setState(() => ({value:value}))
}

onButtonClicked() {
this.setState(state => ({forward: state.value}));
}

render() {
return (

Input: Forward value

);
}
}

class ChildComponent extends React.Component {
constructor(props) {
super(props);
const value = Number(props.value);
this.state = {parent: value, value: value};
this.onButtonClicked = this.onButtonClicked.bind(this);

}

onButtonClicked(event) {
const name = event.target.name;
let value = 0

if (name == "inc") {
value = this.state.value + 1;
} else if(name == "dec") {
value = this.state.value - 1;
}

this.setState(() => ({value: value}))
}

static getDerivedStateFromProps(props, state) {
const parentValue = props.value;
return (parentValue == state.parent) ? null : {parent:parentValue, value: parentValue};
}

render() {
return (

Child: {this.state.value}
+
-

)
}
}

export default ParentComponent;

Michał Stachura
8 miesięcy temu

Do tej pory przykłady były dobrze opisane. Ten tutaj jest słaby i niewiele tłumaczy.

Michał Stachura
8 miesięcy temu

Porównując tą lekcję z poprzednimi i kolejnymi tutaj w przykładzie nie omawiacie nic :). Sama konstrukcja postu jest taka jakby ktoś nie miał na niego czasu.

Zupełnie inaczej to już wygląda w kolejnym wpisie nr 11 gdzie bardzo przystępnie krok po kroku omawiacie poszczególne komponenty. Sam kurs całościowo oceniam bardzo dobrze, ta jedna lekcja nr 10 moim zdaniem mogłaby być dokładniej opisana.

Rafał Sikora
Rafał Sikora
5 miesięcy temu

oki .. myślałem że rozumiem React do póki nie zacząłem komunikować ze sobą komponentów XD
… taki przypadek
-> componentDidMount – pobiera dane, ustawia state i dopiero render() wie wszystko żeby wysłać {…} do gdzie wykonywana jest metoda { setState } ..

.. koniec końców mogę wysłać dane tylko w render .. gdzie NIE mogę tego robić 🙁 ..
index.js:1 Warning: Cannot update during an existing state transition (such as within `render`). Render methods should be a pure function of props and state.
in TabContent (at MainMenuItem.js:34) .. no i jestem w kropce .. gdzie albo jak to robić?

Rafał Sikora
Rafał Sikora
5 miesięcy temu

Comp1 wystamia metodę przez inną class statyczną Static.eventListener:
eventHandler = ( newState = {} ) => {
this.setState( newState );
}
(coś jak ma to miejsce w komunikacji parent-child)
i w
Comp2.render() {
Static.eventListener( { ‚nowe dane’ } ); // tu się pojawia problem
}

co ciekawe jak wprowadzę Comp2.render( Comp3 Static.eventListener( { ‚nowe dane’ } ); dam w componentDidMount() ) problemu już niema … za to kółeczko się zamyka bo dane muszą być zmieniane więc w Comp3 trzeba przenieść Static.eventListener .. do metody która się ‚odświeża’, pytanie można użyć do tego shouldComponentUpdate ?

Andrzej Sulej
Andrzej Sulej
4 miesięcy temu

W temacie Lifting State Up: czy dobrą praktyką jest przekazywanie do obiektów zagnieżdżonych scope’a parent’a np:

Powyższe rozwiązanie pozwala na bezpośredni dostęp do logiki parenta z child’a.

… po 10 latach siedzenia w ExtJS i budowaniu całkiem sporych rozwiązań jestem przyzwyczajony do swobodnego poruszania się po wszystkich instancjach obiektów. Tam naturalnym jest to, że parent posiada handler’y do wszystkich wszystkich obiektów zagnieżdżonych i w drugą stronę każdy child posiada wskaźnik na parent’a.

Andrzej Sulej
Andrzej Sulej
4 miesięcy temu

dzięki na info, tylko czy możesz to jakoś krótko rozwinąć – co jest dobrą praktyką ?
W jaki sposób obiekty mogą z sobą „gadać” w bardziej elastyczny sposób.
Zakładam, że podany przykład React’a z przekazywaniem metody to jeden z najprostrzych sposobów.
… zapewne znajdę odpowiedź w kolejnych częściach kursu … 🙂

Andrzej Sulej
Andrzej Sulej
4 miesięcy temu

dzięki – jest światełko w tunelu 🙂

xyz
xyz
3 miesięcy temu

Jest tu ktoś jeszcze? Mam duży problem z 2 punktem i już sama nie wiem, gdzie szukać pomocy. Tutaj moje wypociny:

class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {
input: null,
forwardValue: null
}
this.handleIncrement = this.handleIncrement.bind(this);
this.handleDecrement = this.handleDecrement.bind(this);
this.handleClick = this.handleClick.bind(this);
this.handleChange = this.handleChange.bind(this);
}

handleIncrement() {
this.setState({input: this.state.input + 1})
}

handleDecrement() {
this.setState({input: this.state.input – 1})
}

handleChange(event) {
this.setState({input: event.target.value});
}

handleClick() {
this.setState({forwardValue: this.state.input});
}

render() {
return (

Propagate to child
{this.state.forwardValue && }

);
}
}

class Child extends React.Component{
render() {
return (

{this.props.number}
+

)
}
}

Łukasz
Łukasz
1 miesiąc temu

Przesyłam moje rozwiązanie ćwiczenia i proszę.o konstruktywną krytykę.
https://pastebin.com/Rhcn4hH4