【React】useEffectでホットリロード時は期待する動作だが、ブラウザリロード時は違う

10622 ワード

コード

pages/hotReload/index.tsx
import { useEffect, useState } from 'react'
import Child from '../../components/hotReload/Child'

export const App = () => {
  const [greeting, setGreeting] = useState('hello')
  const [str, setStr] = useState('')

  useEffect(() => {
    if (str === 'goodbye') {
      const newGreeting = str
      setGreeting(newGreeting)
    }
  }, [str])
  //   }, []) // だとhot reload時にしか動かない

  return (
    <div>
      <p>{greeting}</p>
      <Child setStr={setStr} />
    </div>
  )
}

export default App
components/hotReload/Child.tsx
import { useEffect } from 'react'

type Props = {
  setStr: React.Dispatch<React.SetStateAction<string>>
}

export const Child = ({ setStr }: Props) => {
  useEffect(() => {
    const newStr = 'goodbye'
    setStr(newStr)
  }, [])

  return <div></div>
}

export default Child

説明

期待する動作

ブラウザをリロードした時も、
ホットリロード時もgoodbyeと表示されてほしい。

期待する動作にならない場合

pages/hotReload/index.tsx
  useEffect(() => {
    if (str === 'goodbye') {
      const newGreeting = str
      setGreeting(newGreeting)
    }
  }, []) // 正しく動作するものは }, [str])

とする。

コードを編集して保存し、ホットリロードが走った時

期待通りの動作。

ブラウザをリロードした時

期待とは違う文言。

期待する動作をするコードに修正

pages/hotReload/index.tsx
  useEffect(() => {
    if (str === 'goodbye') {
      const newGreeting = str
      setGreeting(newGreeting)
    }
  }, [str])

とする。
そうすると、ブラウザをリロードしても、
期待通りuseEffectのマウントタイミングにstrが更新された時も含まれるようになる。