🦁

useState / useRef / useFormの初期値にPropsの値を使っている場合の注意点

2022/11/23に公開

こまりごと

useStateやuseRefの初期値はコンポーネントのマウント時にしか設定されません。
そのため、例えば下記のようにstateの初期値にPropsを使っている場合、Propsが更新されてもstateが更新されることはありません。

const Component: React.FC<Data> = ({ data }) => {
    const [state, setState] = useState(data)
  ...
  
  return (
    <>
      ...
    </>
  )
}

解決法

よく見るやりかた

PropsをuseEffectの依存変数に加えることでPropsの更新によりstateを更新できます。

const Component: React.FC<Data> = ({ data }) => {
    const [state, setState] = useState(data)
  useEffect(()=>{
    setState(data)
  },[data])
  ...
  
  return (
    <>
      ...
    </>
  )
}

ベターなやりかた

上記のようにuseEffectを使うと無駄な再描画が発生するため、下記のやり方がスマートです。
コンポーネントのkey属性が変更された場合、コンポーネントは初期化されます。

const ParentComponent: React.FC<{}> = () => {
  const data = useData()
  return <Component key={JSON.stringify(data)} data={data} />
}

const Component: React.FC<Data> = ({ data }) => {
    const [state, setState] = useState(data)
  ...
  
  return (
    <>
      ...
    </>
  )
}

useRefやuseFormも同様

useRefやReact-Hook-FormのuseFormでstateを管理している場合も同様です。
特にuseRefを使っている場合、refをuseEffectの依存変数に加えることはできないため、コンポーネントをマウントし直す必要があります。

参考

https://beta.reactjs.org/learn/you-might-not-need-an-effect#resetting-all-state-when-a-prop-changes

Discussion