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

Vitalyster
źródło

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

Shubham Khatri
źródło
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ę

Hanzla Habib
źródło
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.

Senny
źródło
-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)?

Mwak
źródło
-12

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

Sushil Mahajan
źródło
4
Co nie jest już prawdą w przypadku najnowszych wersji
React