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

кодовый ключ

Ответы:


210

Аргумент, переданный в 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
Это приводит к двойной установке начального состояния, что довольно раздражает. Интересно, можете ли вы установить начальное состояние равным нулю, а затем использовать его 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 () внутри своей функции Avatar (props)?


Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.