Jak mogę zresetować komponent reagujący, w tym cały stan przejściowo osiągalny?


94

Czasami mam elementy reagujące, które są koncepcyjnie stanowe, które chcę zresetować. Idealne zachowanie byłoby równoznaczne z usunięciem starego komponentu i odczytaniem nowego, nieskazitelnego komponentu.

React udostępnia metodę, setStatektóra pozwala na ustawienie własnego jawnego stanu komponentów, ale wyklucza niejawny stan, taki jak fokus przeglądarki i stan formularza, a także wyklucza stan jej elementów podrzędnych. Wyłapywanie wszystkich tych stanów pośrednich może być trudnym zadaniem i wolałbym rozwiązać to rygorystycznie i całkowicie, zamiast grać w walenie w kreta z każdym nowym zaskakującym stanem.

Czy istnieje interfejs API lub wzorzec, aby to zrobić?

Edycja: Zrobiłem trywialny przykład demonstrujący this.replaceState(this.getInitialState())podejście i zestawiając je z this.setState(this.getInitialState())podejściem: jsfiddle - replaceStatejest bardziej wytrzymały.

Odpowiedzi:


210

Aby upewnić się, że niejawny stan przeglądarki, o którym wspominasz, i stan elementów podrzędnych, zostaną zresetowane, możesz dodać keyatrybut do składnika poziomu głównego zwracanego przez render; kiedy się zmieni, ten komponent zostanie wyrzucony i stworzony od podstaw.

render: function() {
    // ...
    return <div key={uniqueId}>
        {children}
    </div>;
}

Nie ma skrótu do resetowania stanu lokalnego poszczególnych składników.


1
Tak z ciekawości, kiedy mówisz „komponent zostanie wyrzucony i utworzony od zera”, czy masz na myśli wyrzucenie wirtualnego DOM i utworzenie go od podstaw, ale aktualizacje DOM będą nadal odbywać się w oparciu o algorytm różnic?
nimgrg

1
@nimgrg Nie, prawdziwe elementy DOM również zostaną odtworzone. (Wirtualny DOM jest już odtwarzany przy każdym renderowaniu, więc jeśli chcesz zachować prawdziwy DOM, po prostu nie ustawiaj keyw tym przypadku.)
Sophie Alpert,

3
@EamonNerbonne W React 0.8 klucze są używane tylko do rozróżniania elementów rodzeństwa w tablicy i zostały zignorowane w katalogu głównym. Zobacz github.com/facebook/react/issues/590 .
Sophie Alpert

Uwaga replaceState()i getInitialState()oba są przestarzałe w nowych reagjach w stylu klas ES6. Użyj this.setState(this._getInitialState())zamiast tego. Nie możesz również nazwać własnej funkcji inicjalizującej stan getInitialState()- reakcja generuje ostrzeżenie - nazwij ją inaczej i jawnie zrób state = this._getInitialState()na najwyższym poziomie klasy.
thom_nic

2
Czy istnieje sposób, aby to zrobić od wewnątrz komponentu bez wymagania, aby strona zewnętrzna przekazała kluczową rekwizyt?
trusktr

14

Właściwie powinieneś unikać replaceStatei używać setStatezamiast tego.

Dokumenty mówią, że replaceState„może zostać całkowicie usunięte w przyszłej wersji React”. Myślę, że z całą pewnością zostanie usunięty, ponieważ replaceStatetak naprawdę nie pasuje do filozofii React. Ułatwia to sprawienie, by komponent React zaczął czuć się jak szwajcarski nóż. To przeszkadza naturalnemu wzrostowi komponentu React, który staje się mniejszy i bardziej celowy.

W Reakcie, jeśli musisz popełnić błąd przy generalizacji lub specjalizacji: dąż do specjalizacji. W konsekwencji drzewo stanu dla twojego komponentu powinno mieć pewną oszczędność (dobrze jest gustownie złamać tę zasadę, jeśli rusztujesz nowy produkt, który zyskuje na popularności).

W każdym razie tak to się robi. Podobna do odpowiedzi Bena (zaakceptowana) powyżej, ale w ten sposób:

this.setState(this.getInitialState());

Również (jak powiedział Ben), aby zresetować „stan przeglądarki”, musisz usunąć ten węzeł DOM. Wykorzystaj moc vdom i użyj nowego keyrekwizytu dla tego komponentu. Nowy render zastąpi hurtowo ten komponent.

Źródła: https://facebook.github.io/react/docs/component-api.html#replacestate


2
To nie zadziała, jeśli bieżący stan zawiera właściwości, które nie są w stanie początkowym. Chociaż nie uważam, że jest to wspaniały „stan” rzeczy, o ile nie można temu w jakiś sposób zapobiec, chciałbym uniknąć zaskakującego załamania. Byłbym w porządku z resetem, który ulega awarii w niektórych przypadkach, ale nie resetem, który subtelnie psuje stan.
Eamon Nerbonne

Nie jestem pewien, czy nadążam. Czy mówisz, że to nie jest równoważne this.replaceState? Bo tak jest.
wle8300

1
@ williamle8300 Nie byłyby równoważne, gdyby nowa właściwość została dodana do stanu gdzieś w cyklu życia komponentu między wywołaniami getInitialState()(powiedzmy, w module obsługi onClick). W tym przypadku ta nowa właściwość będzie nadal obecna po 2 getInitialState().
Graham

@Graham Uważam, że wprowadzanie nowego stanu do komponentu, który nie jest jeszcze zadeklarowany, jest złą praktyką getInitialState. Podobnie jak deklarowanie wszystkich zmiennych w funkcji JS u góry funkcji. Uwaga boczna: rozwiązanie Bena Alperta jest prawie identyczne z moim ... i jest on oficjalnym opiekunem Reacta!
wle8300

1
Obawiam się, że funkcja getInitialState (), a tym samym odpowiedź, jest przestarzała. Aktualizacja byłaby miła.
Martin R.

9

Dodanie keyatrybutu do elementu, który chcesz ponownie zainicjować, spowoduje ponowne załadowanie go za każdym razem, gdy element propslub zostanie stateskojarzony ze zmianą elementu.

klucz = {nowa data (). getTime ()}

Oto przykład:

render() {
  const items = (this.props.resources) || [];
  const totalNumberOfItems = (this.props.resources.noOfItems) || 0;

  return (
    <div className="items-container">
      <PaginationContainer
        key={new Date().getTime()}
        totalNumberOfItems={totalNumberOfItems}
        items={items}
        onPageChange={this.onPageChange}
      />
    </div>
  );
}

1
Lub możesz dodać prostą zmienną licznika całkowitego jako klucz
minimalistyczny
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.