React.useState не перезавантажує стан з реквізиту


95

Я очікую, що стан перезавантажиться при зміні реквізиту, але це не працює, а userзмінна не оновлюється під час наступного useStateдзвінка, що не так?

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

codepen

Відповіді:


214

Аргумент, переданий useState, є початковим станом, подібним до встановлення стану в конструкторі для компонента класу і не використовується для оновлення стану при повторному відтворенні

Якщо ви хочете оновити стан при зміні реквізиту, скористайтеся useEffectхуком

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

Робоча демонстрація


18
При встановленні початкового стану в конструкторі ясно зрозуміти, що конструктор викликається один раз при створенні екземпляра класу. З хуками здається, що useState викликається кожного разу при виклику функції, і кожен раз він повинен ініціалізувати стан, але там трапляється якась незрозуміла "магія".
vitalyster

Можливо, цей допис пролив трохи світла на нього stackoverflow.com/questions/54673188/…
Шубхам Хатрі

якщо вам потрібно об’єднати реквізит у стан, ви застряєте в нескінченному циклі при використанні програми create-response-app, яка вимагає, щоб стан
user210757

2
Це закінчується встановленням початкового стану двічі, що досить дратує. Цікаво, чи можете ви встановити для початкового стану значення null, а потім використовуватиReact.useEffect для встановлення початкового стану кожного разу.
CMCDragonkai

2
Це не працює, якщо стан також контролює візуалізацію. У мене є функціональний компонент, який відображає на основі реквізиту та робить на основі стану. Якщо стан повідомляє компоненту про рендеринг, оскільки він змінився, тоді useEffect запускається і повертає стан до значення за замовчуванням. Це насправді поганий дизайн з їхнього боку.
Грег Верес

1

Функціональні компоненти, де ми використовуємо useStateдля встановлення початкових значень для нашої змінної; якщо ми передаємо початкове значення через реквізит, воно завжди встановлюватиме одне і те ж початкове значення, поки ви не скористаєтесь useEffectхуком,

наприклад, у вашому випадку це зробить вашу роботу

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

Функція, передана useEffect, буде запущена після того, як візуалізація буде зафіксована на екрані.

За замовчуванням ефекти запускаються після кожного завершеного візуалізації, але ви можете запустити їх лише тоді, коли певні значення змінилися.

React.useEffect(FunctionYouWantToRunAfterEveryRender)

якщо ви передаєте лише один аргумент useEffect, він запускатиме цей метод після кожного візуалізації, ви зможете вирішити, коли запускати це FunctionYouWantToRunAfterEveryRender, передаючи другий аргумент useEffect

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

як ви помічаєте, я передаю [props.user] тепер useEffectзапускатиме цю FunctionYouWantToRunAfterEveryRenderфункцію лише тоді, коли props.userбуде змінено

Я сподіваюся, це допоможе вашому розумінню. Повідомте мене, якщо потрібні якісь вдосконалення, дякую


0

Параметр, переданий в, React.useState()є лише початковим значенням для цього стану. React не розпізнає це як зміну стану, лише встановлюючи значення за замовчуванням. Спочатку потрібно встановити стан за замовчуванням, а потім умовно зателефонуватиsetUser(newValue) , який буде визнаний новим станом, і повторно відтворити компонент.

Я рекомендував би обережно оновлювати стан без будь-яких умов, щоб уникнути його постійного оновлення, і, отже, повторний візуалізація кожного разу, коли надходить реквізит. Ви можете розглянути можливість підняття функцій стану до батьківського компонента та передачі стану батьків до цього Аватара як підставки.


-2

Згідно з документацією ReactJS про хуки :

Але що станеться, якщо реквізит друга зміниться, поки компонент знаходиться на екрані? Наш компонент і надалі відображатиме онлайновий статус іншого друга. Це помилка. Ми також можемо спричинити витік пам’яті або збій під час демонтажу, оскільки дзвінок для скасування підписки використовуватиме неправильний ідентифікатор друга.

Ваша єдина взаємодія тут має відбуватися при зміні реквізиту, яка, здається, не працює. Ви можете (як і раніше згідно з документом) використовувати componentDidUpdate (prevProps), щоб активно вловити будь-яке оновлення реквізиту.

PS: У мене недостатньо коду, щоб судити, але чи не могли б ви активно встановити User () всередині функції Аватар (props)?


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.