Kei05
@Kei05

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

Next.jsのinputで発生するエラーの解決方法について

Q&A

Closed

チェックボックスを押すことでサイトのカラーをライト←→ダークと切り替えられるボタンを作っているのですが、コンソールで以下のエラーが発生しました。
修正方法がわからずご教示いただきたいです。

Warning: A component is changing an uncontrolled input to be controlled. This is likely caused by the value changing from undefined to a defined value, which should not happen. Decide between using a controlled or uncontrolled input element for the lifetime of the component. More info: https://reactjs.org/link/controlled-components

実際のコンポーネントのソース

import React, { useEffect, useState } from 'react'

export const SwitchTheme = () => {
  const getInitialColorMode = () => {
    const devicePreferenceMode = window.localStorage.getItem('color-theme')
    const hasDevicePreference = typeof devicePreferenceMode === 'string'

    if (hasDevicePreference) {
      return devicePreferenceMode
    }

    const preference = window.matchMedia('prefers-color-scheme: dark')
    const hasMediaQueryPreference = typeof preference.matches === 'boolean'

    if (hasMediaQueryPreference) {
      return preference.matches ? 'dark' : 'light'
    }

    const themeSwitchChecked = document.getElementById('themeSwitch').checked

    return themeSwitchChecked ? 'dark' : 'light'
  }

  const [darkTheme, setDarkTheme] = useState(undefined)
  const hamdleToggleTheme = (e) => {
    setDarkTheme(e.target.checked)
  }

  useEffect(() => {
    const currentColorMode = getInitialColorMode()
    document.documentElement.style.setProperty('--initial-color-mode', currentColorMode)

    document.documentElement.setAttribute('data-theme', currentColorMode)
    setDarkTheme(currentColorMode === 'dark' ? true : false)
  }, [])

  useEffect(() => {
    if (darkTheme != undefined) {
      if (darkTheme) {
        document.documentElement.setAttribute('data-theme', 'dark')
        window.localStorage.setItem('color-theme', 'dark')
      } else {
        document.documentElement.setAttribute('data-theme', 'light')
        window.localStorage.setItem('color-theme', 'light')
      }
    }
  })

  return (
    <label className={styles.label} onChange={hamdleToggleTheme}>
      <input type='checkbox' name='' id='themeSwitch' checked={darkTheme} />
    </label>
  )
}
0

1Answer

const [darkTheme, setDarkTheme] = useState(undefined)

多分ここが問題で、

setDarkTheme(e.target.checked)

ここでもやっているように要はbooleanを設定したいんだと思います。
だけど初期値がundefinedなので実際は3パターンの動作を用意しています。

Reactでinput要素の値を変化させる時にundefined(uncontrolled)から今回で言うtrue/falseに切り替えることは推奨されていなかったと思います。
なのでWarningが出ているのかなと。

そして一般的にはlightモードがデフォルトであって、選択肢としてdarkモードがあるだけだと思うので、2パターンの動作を用意するだけで良い気はします。

const [darkTheme, setDarkTheme] = useState(false) // デフォルトとしてはlightモード

0Like

Comments

  1. @Kei05

    Questioner

    細かく説明いただきありがとうございます!無事解決できました。

Your answer might help someone💌