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

Spodziewam się, że stan przeładuje się przy zmianie właściwości, ale to nie działa i user zmienna nie jest aktualizowana przy następnym wywołaniu useState, 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

Author: Bill Keller, 2019-02-25

6 answers

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

Jeśli chcesz zaktualizować stan przy zmianie prop, użyj useEffect hook

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>);
}

Demo robocze

 261
Author: Shubham Khatri,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-02-25 12:18:05

Parametr przekazany do React.useState() jest tylko wartością początkową dla tego stanu. React nie rozpozna tego jako zmieniając Stan, ustawiając jedynie jego domyślną wartość. Najpierw należy ustawić domyślny stan, a następnie warunkowo wywołać setUser(newValue), który zostanie rozpoznany jako nowy stan i ponownie wyrenderować komponent.

Zalecałbym ostrożność w aktualizacji stanu bez jakiegoś warunku, aby nie aktualizować go stale, a zatem ponownie renderować za każdym razem są odbierane. Warto rozważyć przeniesienie funkcji stanu do komponentu nadrzędnego i przekazanie stanu rodzica do tego awatara jako rekwizytu.

 2
Author: Drowsy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-02-25 12:15:18

Komponenty funkcyjne, w których używamy useState do ustawienia wartości początkowych do naszej zmiennej, jeśli przekażemy wartość początkową przez właściwości, będzie ona zawsze ustawiać tę samą wartość początkową, dopóki nie użyjesz useEffect Hooka,

Na przykład twój przypadek to zrobi Twoją pracę

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

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

Domyślnie efekty uruchamiane są po każdym zakończonym renderowaniu, ale można je uruchamiać tylko wtedy, gdy określone wartości mają zmieniony.

React.useEffect(FunctionYouWantToRunAfterEveryRender)

Jeśli przekażesz tylko jeden argument do useEffect, to ta metoda uruchomi się po każdym renderowaniu możesz zdecydować, kiedy odpalić FunctionYouWantToRunAfterEveryRender, przekazując drugi argument do useEffect

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

Jak zauważyłeś, przekazuję [rekwizyty.użytkownik] teraz useEffect uruchomi tę funkcję FunctionYouWantToRunAfterEveryRender tylko wtedy, gdy props.user zostanie zmieniona

Mam nadzieję, że to pomoże Ci zrozumieć daj mi znać, jeśli wymagane są jakieś ulepszenia dzięki

 2
Author: Hanzla Habib,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-07-19 16:15:52

Stworzyłem własne Hooki w ten sposób:

const usePrevious = value => {
   const ref = React.useRef();

   React.useEffect(() => {
       ref.current = value;
   }, [value]);

   return ref.current;
}

const usePropState = datas => {
    const [dataset, setDataset] = useState(datas);
    const prevDatas = usePrevious(datas);

    const handleChangeDataset = data => setDataset(data);

    React.useEffect(() => {
        if (!deepEqual(datas, prevDatas)) // deepEqual is my function to compare object/array using deep-equal
            setDataset(datas);
    }, [datas, prevDatas]);

    return [
        dataset,
        handleChangeDataset
    ]
}

Do użycia:

const [state, setState] = usePropState(props.datas);
 0
Author: Oan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2021-01-29 07:53:02

Zgodnie z dokumentacją ReactJS o Hookach:

Ale co się stanie, jeśli rekwizyt znajomego zmieni się, gdy komponent jest na ekranie? Nasz komponent będzie nadal wyświetlał status online innego znajomego. To jest pluskwa. Spowodowalibyśmy również wyciek pamięci lub awarię podczas odmontowywania, ponieważ połączenie rezygnacji z subskrypcji używałoby niewłaściwego identyfikatora znajomego.

Twoja jedyna interakcja tutaj powinna mieć miejsce na zmianie rekwizytów, co wydaje się nie działać. Mógłbyś (nadal zgodnie z doc) użyj komponentudidupdate (prevProps), aby proaktywnie złapać każdą aktualizację właściwości.

PS: nie mam wystarczająco dużo kodu do oceny, ale czy nie mógłbyś aktywnie ustawić user () wewnątrz funkcji Avatara (rekwizytów)?

 -3
Author: Mwak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-02-25 12:09:16

W reactowym świecie, powinieneś zaktualizować swój stan w funkcji componentWillRecieveProps (nextProps), w takich przypadkach.

 -13
Author: Sushil Mahajan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-02-25 12:22:25