React.useState nie przeładowuje stanu z właściwości


109

Oczekuję, że stan załaduje się ponownie po zmianie właściwości, ale to nie działa i userzmienna nie jest aktualizowana przy następnym useStatewywołaniu, co jest nie tak?

function Avatar(props) {
  const [user, setUser] = React.useState({...props.user});
  return user.avatar ? 
         (<img src={user.avatar}/>)
        : (<p>Loading...</p>);
}

codepen

Odpowiedzi:


246

Argument przekazany do useState jest stanem początkowym, podobnie jak ustawienie stanu w konstruktorze dla składnika klasy i nie jest używany do aktualizowania stanu przy ponownym renderowaniu

Jeśli chcesz aktualizować stan przy zmianie właściwości, użyj useEffecthooka

function Avatar(props) {
  const [user, setUser] = React.useState({...props.user});

  React.useEffect(() => {
      setUser(props.user);
  }, [props.user])

  return user.avatar ? 
         (<img src={user.avatar}/>)
        : (<p>Loading...</p>);
}

Działające demo


21
Podczas ustawiania stanu początkowego w konstruktorze, jasne jest, aby zrozumieć, że konstruktor jest wywoływany raz podczas tworzenia instancji klasy. Z hookami wygląda na to, że useState jest wywoływane za każdym razem przy wywołaniu funkcji i za każdym razem, gdy powinno inicjalizować stan, ale dzieje się tam jakaś niewyjaśniona „magia”.
vitalyster

Może ten post rzucił trochę światła na to stackoverflow.com/questions/54673188/…
Shubham Khatri

1
jeśli chcesz scalić rekwizyty w stan, utkniesz w nieskończonej pętli podczas korzystania z aplikacji create
-reak

2
To kończy się dwukrotnym ustawieniem stanu początkowego, co jest dość denerwujące. Zastanawiam się, czy można ustawić stan początkowy na null, a następnie użyć React.useEffectdo ustawienia stanu początkowego za każdym razem.
CMCDragonkai

3
To nie działa, jeśli stan kontroluje również renderowanie. Mam funkcjonalny komponent, który renderuje się na podstawie właściwości i renderuje na podstawie stanu. Jeśli stan mówi komponentowi, aby renderował się, ponieważ się zmienił, to useEffect działa i ustawia stan z powrotem na wartość domyślną. To naprawdę zły projekt z ich strony.
Greg Veres,

2

Komponenty funkcjonalne, w których używamy useStatedo ustawiania wartości początkowych naszej zmiennej, jeśli przekażemy wartość początkową przez właściwości, będzie ona zawsze ustawiała tę samą wartość początkową, dopóki nie użyjesz useEffecthooka,

na przykład w twoim przypadku to wykona twoją pracę

 React.useEffect(() => {
      setUser(props.user);
  }, [props.user])

Funkcja przekazana do useEffect zostanie uruchomiona po zatwierdzeniu renderowania na ekranie.

Domyślnie efekty są uruchamiane po każdym ukończonym renderowaniu, ale możesz je uruchomić tylko wtedy, gdy zmienią się określone wartości.

React.useEffect(FunctionYouWantToRunAfterEveryRender)

jeśli przekażesz tylko jeden argument do useEffect, będzie on uruchamiał tę metodę po każdym renderowaniu, możesz zdecydować, kiedy to uruchomić FunctionYouWantToRunAfterEveryRender, przekazując drugi argument do useEffect

React.useEffect(FunctionYouWantToRunAfterEveryRender, [props.user])

jak zauważyłeś, przechodzę przez [props.user] teraz useEffecturuchomi tę FunctionYouWantToRunAfterEveryRenderfunkcję tylko wtedy, gdy props.userzostanie zmieniona

Mam nadzieję, że pomoże to w zrozumieniu, daj mi znać, jeśli wymagane są jakieś ulepszenia, dziękuję


1

Parametr przekazany do React.useState()jest tylko wartością początkową dla tego stanu. React nie rozpozna tego jako zmiany stanu, ustawi tylko domyślną wartość. Będziesz chciał początkowo ustawić stan domyślny, a następnie wywołać warunkowe setUser(newValue), co zostanie rozpoznane jako nowy stan i ponownie wyrenderować komponent.

Zalecałbym ostrożność przy aktualizowaniu stanu bez jakiegokolwiek warunku, aby nie był on stale aktualizowany, a zatem ponowne renderowanie za każdym razem, gdy otrzymywane są rekwizyty. Możesz rozważyć przeniesienie funkcji stanu do komponentu nadrzędnego i przekazanie stanu rodzica do tego awatara jako rekwizytu.


-2

Zgodnie z dokumentacją ReactJS o hookach :

Ale co się stanie, jeśli rekwizyt przyjaciela zmieni się, gdy komponent jest na ekranie? Nasz komponent będzie nadal wyświetlał status online innego znajomego. To jest błąd. Moglibyśmy również spowodować wyciek pamięci lub awarię podczas odmontowywania, ponieważ wywołanie anulowania subskrypcji używałoby niewłaściwego identyfikatora znajomego.

Twoja jedyna interakcja powinna mieć miejsce przy zmianie rekwizytów, która wydaje się nie działać. Możesz (nadal zgodnie z dokumentacją) użyć komponentu componentDidUpdate (prevProps), aby aktywnie przechwytywać każdą aktualizację właściwości.

PS: Nie mam wystarczającej ilości kodu do oceny, ale czy nie mógłbyś aktywnie ustawićUser () wewnątrz funkcji Avatar (props)?


-12

W świecie reakcji należy w takich przypadkach zaktualizować swój stan w funkcji componentWillRecieveProps (nextProps).


4
Co nie jest już prawdą w przypadku najnowszych wersji
React
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.