React.useState не перезагружает состояние из реквизита

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

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

codepen

Ответ 1

Аргумент, передаваемый 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>);
}

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

Ответ 2

Согласно документации ReactJS о крюках:

Но что произойдет, если друг изменяет реквизит, когда компонент находится на экране? Наш компонент будет продолжать отображать онлайн-статус другого друга. Это ошибка. Мы также могли бы вызвать утечку памяти или сбой при размонтировании, так как вызов отмены подписки будет использовать неверный идентификатор друга.

Ваше единственное взаимодействие здесь должно происходить при смене реквизита, которая, похоже, не работает. Вы можете (все еще в соответствии с документом) использовать componentDidUpdate (prevProps), чтобы заранее перехватить любое обновление реквизита.

PS: мне не хватает кода, чтобы судить, но разве вы не можете активно устанавливать uUser() внутри своей функции Avatar (props)?

Ответ 3

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

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

Ответ 4

В мире реагирования вам следует обновить свое состояние в функции componentWillRecieveProps (nextProps), в таких случаях.