Kiedy stosować React callState callback

191

Gdy zmienia się stan składnika reagującego, wywoływana jest metoda renderowania. Dlatego w przypadku każdej zmiany stanu można wykonać akcję w ciele metod renderowania. Czy istnieje zatem szczególny przypadek użycia dla wywołania zwrotnego setState?

Sahil Jain
źródło
4
Obecnie nie jest jasne, o co pytasz. Czy możesz podać kod?
Davin Tryon
2
Wywołanie zwrotne setState służy do wszystkiego, co chcesz zrobić po tym, jak stan DEFINITYCZNIE został zmieniony. Ponieważ setState jest asynchroniczny, jeśli chcesz wywołać fx i być PEWNYM, że nowy stan jest załadowany, to właśnie do tego służy callback
Jayce444
3
Przypadek użycia wywołania zwrotnego setState jest dość jasny. Używasz go, gdy chcesz, aby funkcja działała po zaktualizowaniu stanu SPECYFICZNEGO. Jeśli render()zamiast tego wstawisz tę funkcję , będzie ona działać za każdym razem, gdy DOWOLNY stan zostanie zaktualizowany, co prawdopodobnie nie jest tym, czego chcesz. Dzięki temu Twój kod będzie mniej czytelny i logiczny.
M3RS

Odpowiedzi:

224

Tak, ponieważ setStatedziała w pewien asynchronoussposób. Oznacza to, że po wywołaniu setStatedo this.statezmiennej nie jest natychmiast zmienić. więc jeśli chcesz wykonać akcję natychmiast po ustawieniu stanu na zmienną stanu, a następnie zwrócić wynik, przydatne będzie wywołanie zwrotne

Rozważ poniższy przykład

....
changeTitle: function changeTitle (event) {
  this.setState({ title: event.target.value });
  this.validateTitle();
},
validateTitle: function validateTitle () {
  if (this.state.title.length === 0) {
    this.setState({ titleError: "Title can't be blank" });
  }
},
....

Powyższy kod może nie działać zgodnie z oczekiwaniami, ponieważ titlezmienna mogła nie zostać zmutowana przed wykonaniem na niej sprawdzania poprawności. Teraz możesz się zastanawiać, czy możemy przeprowadzić walidację w render()samej funkcji, ale byłby lepszy i czystszy sposób, gdybyśmy mogli sobie z tym poradzić w samej funkcji changeTitle, ponieważ dzięki temu twój kod byłby bardziej zorganizowany i zrozumiały.

W takim przypadku przydatne jest oddzwonienie

....
changeTitle: function changeTitle (event) {
  this.setState({ title: event.target.value }, function() {
    this.validateTitle();
  });

},
validateTitle: function validateTitle () {
  if (this.state.title.length === 0) {
    this.setState({ titleError: "Title can't be blank" });
  }
},
....

Innym przykładem będzie sytuacja, gdy chcesz dispatchi działanie, gdy stan się zmieni. będziesz chciał to zrobić w trybie oddzwaniania, a nie w taki render()sposób, w jaki będzie on wywoływany za każdym razem, gdy nastąpi ponowne wyrenderowanie, a zatem istnieje wiele takich scenariuszy, w których będziesz potrzebował oddzwonienia.

Innym przypadkiem jest API Call

Może się zdarzyć, że konieczne będzie wywołanie interfejsu API na podstawie konkretnej zmiany stanu, jeśli zrobisz to w metodzie renderowania, będzie ona wywoływana przy każdej onStatezmianie renderowania lub dlatego, że niektóre Prop przeszły na Child Componentzmienioną.

W takim przypadku należy użyć a, setState callbackaby przekazać zaktualizowaną wartość stanu do wywołania API

....
changeTitle: function (event) {
  this.setState({ title: event.target.value }, () => this.APICallFunction());
},
APICallFunction: function () {
  // Call API with the updated value
}
....
Shubham Khatri
źródło
3
Rozumiem, że ma charakter asynchroniczny. Moje pytanie brzmiało: czy jest coś konkretnego, co może być użyte tylko do wywołania zwrotnego setState, być może ciało renderujące metody może nie obsługiwać (Coś poza, powiedzmy, lepszą czytelnością kodu).
Sahil Jain
Sprawdzanie poprawności @SahilJain jest poprawnym przykładem, nie będziesz chciał obsługiwać go w funkcji render (), ponieważ będzie on wywoływany za każdym razem, gdy wprowadzisz jakąkolwiek zmianę w render (), będziesz chciał wywołać ją tylko wtedy, gdy zmieni się tylko dane wejściowe, a zatem w samej funkcji
Shubham Khatri
React zabrania zmiany stanu podczas renderowania. Więc jego prawo do umieszczenia sprawdzania poprawności w wywołaniu zwrotnym.
webdeb
if (this.title.length === 0) {powinno być this.state.title.length, prawda?
Dmitry Minkovsky,
4
Przypadek pierwszego użycia prawdopodobnie nie jest dobrym pomysłem. Wywołania zwrotne setState uruchamiają się po ponownym renderowaniu, więc powoduje to podwójne renderowanie bez uzasadnionego powodu. To jest dokładnie cel argumentu funkcji (updater). Możesz po prostu uruchomić, setState(state => state.title.length ? { titleError: "Title can't be blank" } : null)a zmiany zostaną nałożone. Nie ma potrzeby podwójnego renderowania.
R Esmond,
47
this.setState({
    name:'value' 
},() => {
    console.log(this.state.name);
});
Araz Babayev
źródło
14
Dziękujemy za ten fragment kodu, który może zapewnić pewną ograniczoną, natychmiastową pomoc. Właściwe wyjaśnienie byłoby znacznie poprawić swoją długoterminową wartość pokazując dlaczego jest to dobre rozwiązanie problemu, a byłoby bardziej użyteczne dla czytelników przyszłości z innymi, podobnymi pytaniami. Proszę edytować swoją odpowiedź dodać kilka wyjaśnień, w tym założeń już wykonanych.
Machavity
1
Jeśli chcesz wywołać funkcję po zmianie stanu, możesz użyć tej metody.
Araz Babayev
co jeśli chcesz ustawić wiele nazwisk państwowych, takich jak imię, imię itp.?
Sumanth Varada,
44

1. przypadek użycia, który przychodzi mi na myśl, to apiwywołanie, które nie powinno przejść do renderowania, ponieważ będzie działać w celu eachzmiany stanu. Wywołanie interfejsu API powinno być wykonywane tylko przy specjalnej zmianie stanu, a nie przy każdym renderowaniu.

changeSearchParams = (params) => {
  this.setState({ params }, this.performSearch)
} 

performSearch = () => {
  API.search(this.state.params, (result) => {
    this.setState({ result })
  });
}

Dlatego w przypadku każdej zmiany stanu można wykonać akcję w ciele metod renderowania.

Bardzo zła praktyka , ponieważ render-metoda powinna być czysta, oznacza to, że nie należy wykonywać żadnych akcji, zmian stanu, wywołań interfejsu API, po prostu skomponuj swój widok i zwróć go. Działania należy wykonywać tylko w przypadku niektórych zdarzeń. Renderowanie nie jest zdarzeniem, ale componentDidMountna przykład.

webdeb
źródło
25

Rozważ połączenie setState

this.setState({ counter: this.state.counter + 1 })

POMYSŁ

setState może być wywoływany w funkcji asynchronicznej

Więc nie możesz polegać this. Jeśli powyższe wywołanie zostało wykonane wewnątrz funkcji asynchronicznej this, odniesie się do stanu komponentu w tym momencie czasu, ale spodziewaliśmy się, że odniesie się to do właściwości wewnątrz stanu w czasie wywołania setState lub rozpoczęcia zadania asynchronicznego. Ponieważ zadaniem było wywołanie asynchroniczne, właściwość mogła się z czasem zmienić. Dlatego nie można wiarygodnie użyć thissłowa kluczowego w odniesieniu do niektórych właściwości stanu, dlatego używamy funkcji zwrotnej, której argumentami są previousState i rekwizyty, co oznacza, kiedy zadanie asynchroniczne zostało wykonane i nadszedł czas na aktualizację stanu za pomocą wywołania setState prevState będzie odnosić się do stanu teraz, gdy setState jeszcze się nie zaczął Zapewnienie niezawodności, że nextState nie zostanie uszkodzony.

Błędny kod: prowadziłby do uszkodzenia danych

this.setState(
   {counter:this.state.counter+1}
 );

Poprawny kod z setState z funkcją oddzwaniania:

 this.setState(
       (prevState,props)=>{
           return {counter:prevState.counter+1};
        }
    );

Dlatego za każdym razem, gdy potrzebujemy zaktualizować nasz obecny stan do następnego stanu na podstawie wartości posiadanej przez właściwość właśnie teraz, a wszystko to dzieje się w sposób asynchroniczny, dobrym pomysłem jest użycie setState jako funkcji wywołania zwrotnego.

Próbowałem to wyjaśnić tutaj codepen CODE PEN

Aniket Jha
źródło