React.useStateは小道具から状態をリロードしません


108

小道具の変更時に状態がリロードされることを期待していますが、これは機能せず、user変数は次のuseState呼び出しで更新されません。何が問題になっていますか?

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

codepen

回答:


242

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

作業デモ


21
コンストラクターで初期状態を設定する場合、クラスインスタンスの作成時にコンストラクターが1回呼び出されることを理解するのは明らかです。フックを使用すると、useStateは関数呼び出しのたびに呼び出され、状態を初期化する必要があるように見えますが、説明のつかない「魔法」がそこで発生します。
バイタリスター

たぶんこの記事はそれにいくつかの光を当てるstackoverflow.com/questions/54673188/...
Shubhamカトリ

1
小道具を状態にマージする必要がある場合、状態が依存関係配列にある必要があるcreate-react-appを使用すると、無限ループに
陥ります

2
これは、初期状態を2回設定することになり、かなり面倒です。初期状態をnullReact.useEffectに設定してから、毎回初期状態を設定できるのではないかと思います。
CMCDragonkai

3
状態がレンダリングも制御している場合、これは機能しません。小道具に基づいてレンダリングし、状態に基づいてレンダリングする機能コンポーネントがあります。状態が変更されたためにコンポーネントにレンダリングするように指示した場合、useEffectが実行され、状態がデフォルト値に戻ります。これは彼らの側では本当に悪いデザインです。
GregVeres20年

2

useState変数に初期値を設定するために使用する機能コンポーネント。小道具を介して初期値を渡すと、useEffectフックを使用しない限り、常に同じ初期値が設定されます。

たとえばあなたの場合これはあなたの仕事をします

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

useEffectに渡された関数は、レンダリングが画面にコミットされた後に実行されます。

デフォルトでは、エフェクトはレンダリングが完了するたびに実行されますが、特定の値が変更された場合にのみエフェクトを起動するように選択できます。

React.useEffect(FunctionYouWantToRunAfterEveryRender)

useEffectに引数を1つだけ渡すと、レンダリングのたびにこのメソッドが実行されますFunctionYouWantToRunAfterEveryRender。useEffectに2番目の引数を渡すことで、これをいつ起動するかを決定できます。

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

お気づきのとおり、[props.user]を渡すuseEffectFunctionYouWantToRunAfterEveryRenderprops.userが変更された場合にのみこの関数が起動します

これがあなたの理解に役立つことを願っています改善が必要な場合は私に知らせてくださいありがとう


1

渡されるパラメータはReact.useState()、その状態の初期値のみです。Reactは、状態の変更としてそれを認識せず、デフォルト値を設定するだけです。最初にデフォルトの状態を設定してから、条件付きでを呼び出しますsetUser(newValue)。これは新しい状態として認識され、コンポーネントを再レンダリングします。

状態が常に更新されないように、何らかの条件なしで状態を更新するように注意することをお勧めします。したがって、小道具を受け取るたびに再レンダリングします。状態機能を親コンポーネントに引き上げ、親の状態を小道具としてこのアバターに渡すことを検討することをお勧めします。


-2

フックに関するReactJSのドキュメントによると:

しかし、コンポーネントが画面に表示されているときに友達の小道具が変わるとどうなりますか?私たちのコンポーネントは、別の友達のオンラインステータスを引き続き表示します。これはバグです。また、unsubscribe呼び出しで間違ったフレンドIDが使用されるため、アンマウント時にメモリリークやクラッシュが発生します。

ここでの唯一のやりとりは、小道具の変更時に発生するはずですが、機能していないようです。(まだドキュメントによると)componentDidUpdate(prevProps)を使用して、小道具の更新をプロアクティブにキャッチすることができます。

PS:判断するのに十分なコードがありませんが、アバター(小道具)関数内でアクティブにユーザー()を設定できませんでしたか?


-12

このような場合、react worldでは、componentWillRecieveProps(nextProps)関数で状態を更新する必要があります。


4
これは、reactの最新バージョンには当てはまりません
ShubhamKhatri19年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.