Articles

Zrozumienie Reactowego` setState ’

komponenty Reactowe mogą i często mają stan. Stan może być wszystkim, ale pomyśl o tym, czy użytkownik jest zalogowany, czy nie i wyświetla prawidłową nazwę Użytkownika na podstawie tego, które konto jest aktywne. Lub szereg postów na blogu. Lub jeśli modal jest otwarty lub nie i która karta w nim jest aktywna.

komponenty Reactowe z interfejsem renderowania stanu w oparciu o ten stan. Gdy zmienia się stan komponentów, zmienia się również interfejs komponentów.

To sprawia, że zrozumienie, kiedy i jak zmienić stan komponentu jest ważne. Pod koniec tego samouczka powinieneś wiedzieć, jak działa setState I być w stanie uniknąć typowych pułapek, które wielu z nas uderza podczas uczenia się Reacta.

działanie `setState ()`

setState() jest jedynym legalnym sposobem aktualizacji stanu po początkowej konfiguracji stanu. Załóżmy, że mamy komponent wyszukiwania i chcemy wyświetlić wyszukiwany termin przesłany przez użytkownika.

oto konfiguracja:

import React, { Component } from 'react'class Search extends Component { constructor(props) { super(props) state = { searchTerm: '' } }}

przekazujemy pusty łańcuch jako wartość i, aby zaktualizować stansearchTerm, musimy wywołaćsetState().

setState({ searchTerm: event.target.value })

tutaj przekazujemy obiekt dosetState(). Obiekt zawiera część stanu, którą chcemy zaktualizować, która w tym przypadku jest wartością searchTerm. React pobiera tę wartość i łączy ją z obiektem, który jej potrzebuje. Jest to coś w rodzaju komponentu Search, który pyta, czego powinien użyć dla wartości searchTerm I setState() odpowiada odpowiedzią.

to w zasadzie uruchamia proces, który react wywołuje pojednanie. Proces uzgadniania to sposób, w jaki React aktualizuje DOM, wprowadzając zmiany w komponencie w oparciu o zmianę stanu. Gdy zostanie wywołane żądanie do setState(), React utworzy nowe drzewo zawierające elementy reaktywne w komponencie (wraz z zaktualizowanym stanem). To drzewo służy do określenia, w jaki sposób interfejs użytkownika komponentu Search powinien się zmienić w odpowiedzi na zmianę stanu, porównując go z elementami poprzedniego drzewa. React wie, które zmiany zaimplementować i zaktualizuje tylko części drzewa DOM, gdy będzie to konieczne. Dlatego React jest szybki.

To brzmi jak dużo, ale podsumowując przepływ:

  • mamy komponent wyszukiwania, który wyświetla szukany termin
  • ten szukany termin jest obecnie pusty
  • użytkownik przesyła szukany termin
  • ten termin jest przechwytywany i przechowywany przez setState jako wartość
  • następuje uzgadnianie

  • i React zauważa zmianę wartości
  • React instruuje komponent wyszukiwania, aby zaktualizował wartość, a szukany termin jest scalany w

proces uzgadniania niekoniecznie zmienia całe drzewo, z wyjątkiem sytuacji, gdy korzeń drzewa zmienia się w ten sposób:

// old<div> <Search /></div>// new<span> <Search /></span>

wszystkie tagi<div> stają się tagami<span>, a całe drzewo komponentów zostanie zaktualizowane.

zasadą jest, aby nigdy nie mutować bezpośrednio stanu. Zawsze używaj setState(), aby zmienić stan. Bezpośrednie modyfikowanie stanu, tak jak Poniższy fragment, nie spowoduje ponownego renderowania komponentu.

// do not do thisthis.state = { searchTerm: event.target.value}

przekazanie funkcji do `setState ()`

aby zademonstrować ten pomysł dalej, stwórzmy prosty licznik, który zwiększa i zmniejsza po kliknięciu.

Zobacz Długopis setState Pen autorstwa Kingsley Silas Chijioke (@kinsomicrote) na CodePen.

zarejestrujmy komponent i zdefiniujmy znaczniki dla interfejsu użytkownika:

class App extends React.Component {state = { count: 0 }handleIncrement = () => { this.setState({ count: this.state.count + 1 })}handleDecrement = () => { this.setState({ count: this.state.count - 1 })} render() { return ( <div> <div> {this.state.count} </div> <button onClick={this.handleIncrement}>Increment by 1</button> <button onClick={this.handleDecrement}>Decrement by 1</button> </div> ) }}

w tym momencie licznik po prostu zwiększa lub zmniejsza liczbę o 1 przy każdym kliknięciu.

ale co jeśli zamiast tego chcemy zwiększyć lub zmniejszyć o 3? Możemy spróbować wywołaćsetState() trzy razy whandleDecrement IhandleIncrement funkcje takie jak ta:

handleIncrement = () => { this.setState({ count: this.state.count + 1 }) this.setState({ count: this.state.count + 1 }) this.setState({ count: this.state.count + 1 })}handleDecrement = () => { this.setState({ count: this.state.count - 1 }) this.setState({ count: this.state.count - 1 }) this.setState({ count: this.state.count - 1 })}

Jeśli kodujesz w domu, możesz być zaskoczony, że nie działa.

powyższy fragment kodu jest równoważny:

Object.assign( {}, { count: this.state.count + 1 }, { count: this.state.count + 1 }, { count: this.state.count + 1 },)

Object.assign() służy do kopiowania danych z obiektu źródłowego do obiektu docelowego. Jeśli dane kopiowane ze źródła do celu mają te same klucze, jak w naszym przykładzie, wygrywa ostatni obiekt. Oto prostsza wersja tego, jak działa Object.assign();

let count = 3const object = Object.assign({}, {count: count + 1}, {count: count + 2}, {count: count + 3});console.log(object);// output: Object { count: 6 }

więc zamiast wywoływania trzy razy, dzieje się to tylko raz. Można to naprawić, przekazując funkcję do setState(). Tak jak przekazujesz obiekty do setState(), możesz również przekazywać funkcje, i to jest wyjście z sytuacji powyżej.

Jeśli edytujemyhandleIncrement funkcja wygląda tak:

handleIncrement = () => { this.setState((prevState) => ({ count: prevState.count + 1 })) this.setState((prevState) => ({ count: prevState.count + 1 })) this.setState((prevState) => ({ count: prevState.count + 1 }))}

…możemy teraz zwiększyć liczbę trzy razy jednym kliknięciem.

w tym przypadku, zamiast scalać, React kolejkuje wywołania funkcji w kolejności, w jakiej została wykonana i aktualizuje cały stan. Spowoduje to uaktualnienie stanu licznika do 3 zamiast 1.

Uzyskaj dostęp do poprzedniego stanu za pomocą narzędzia Updater

podczas budowania aplikacji Reactowych, są chwile, kiedy chcesz obliczyć stan na podstawie poprzedniego stanu komponentu. Nie zawsze można zaufać this.state, aby utrzymać prawidłowy stan natychmiast po wywołaniu setState(), ponieważ jest on zawsze równy stanowi renderowanemu na ekranie.

wróćmy do naszego przykładu, aby zobaczyć, jak to działa. Powiedzmy, że mamy funkcję, która zmniejsza naszą liczbę o 1. Ta funkcja wygląda następująco:

changeCount = () => { this.setState({ count: this.state.count - 1})}

to czego chcemy to możliwość zmniejszenia o 3. FunkcjachangeCount() jest wywoływana trzykrotnie w funkcji obsługującej Zdarzenie click, w ten sposób.

handleDecrement = () => { this.changeCount() this.changeCount() this.changeCount()}

za każdym razem, gdy zostanie kliknięty przycisk zmniejszania, liczba zmniejszy się o 1 zamiast 3. Dzieje się tak, ponieważ this.state.count nie jest aktualizowany, dopóki komponent nie zostanie ponownie wyrenderowany. Rozwiązaniem jest użycie aktualizatora. Aktualizator pozwala uzyskać dostęp do bieżącego stanu i natychmiast użyć go do aktualizacji innych elementów. Tak więc funkcjachangeCount() będzie wyglądać tak.

changeCount = () => { this.setState((prevState) => { return { count: prevState.count - 1} })}

teraz nie jesteśmy zależni od wyniku this.state. Stany countsą zbudowane na sobie, dzięki czemu jesteśmy w stanie uzyskać dostęp do właściwego stanu, który zmienia się przy każdym wywołaniu dochangeCount().

setState() należy traktować asynchronicznie — innymi słowy, nie zawsze należy oczekiwać, że stan się zmienił po wywołaniusetState().

zamykanie

podczas pracy zsetState() są to najważniejsze rzeczy, które powinieneś wiedzieć:

  • Aktualizacja do stanu komponentu powinna być wykonana za pomocąsetState()
  • możesz przekazać obiekt lub funkcję dosetState()
  • przekaż funkcję, gdy możesz wielokrotnie aktualizować stan
  • nie zależy od tego.stan natychmiast po wywołaniu setState() I zamiast tego użyj funkcji updater.