LoginSignup
24
9

More than 3 years have passed since last update.

React: フックで値を定めた<input>要素に制御されたコンポーネントを使うよう警告が出る ー Warning: Changing uncontrolled input

Posted at

フックuseState()でテキスト入力フィールド(<input type="text">)をコントロールしようとしたら、ブラウザコンソールに何やら警告が出てしまいました。

制御されたコンポーネントを使うよう促す警告

具体的にはつぎのメッセージで、制御されていない<input type="text">要素を制御されたコンポーネントに変換しようとしていると警告しています。コントロールしたいのなら、制御されたコンポーネントを使わなければならないということのようです。

Warning: A component is changing an uncontrolled input of type text to be controlled. Input elements should not switch from uncontrolled to controlled (or vice versa). Decide between using a controlled or uncontrolled input element for the lifetime of the component.

警告(Warning)メッセージから検索してこの記事にたどり着き、とにかく結論が知りたいという方は、フックuseState()に初期値を与えてください。

// const [text, setText] = useState();
const [text, setText] = useState('');  // 初期値を与える

では改めて、経緯からお話ししましょう。

警告を受けた関数コンポーネントのコード

警告を受けた関数コンポーネントのコードは、きわめて単純化するとつぎのとおりです。これで前掲の警告が示されます。CodeSandbox「React: Warning - Changing uncontrolled input with hook」にサンプルを掲げましたので、実際の動きはこちらでお確かめください。フィールドにテキストを入力した最初に、ブラウザコンソールにメッセージが出力されます。警告ですので、動作しないわけではありません。

function App() {
  const [text, setText] = useState();
  const handleChange = (event) => {
    const target = event.target;
    setText(target.value);
  };
  return (
    <div>
      <input type="text"
        value={text}
        onChange={handleChange}
      />
    </div>
  );
}

クラスコンポーネントでは警告されない

警告メッセージはさらに、詳しくはこちらを見るようにと「制御されたコンポーネント」の説明がリンクされています。ただ、例示されているコードはクラスコンポーネントです。たしかに、つぎのようなクラスコンポーネントに書き替えれば警告は出ません。

class App extends React.Component {
  constructor() {
    super();
    this.state = {};
    this.handleChange = this.handleChange.bind(this);
  }
  handleChange(event) {
    const target = event.target;
    console.log('change:', target.value);
  };
  render() {
    return (
      <div>
        <input type="text"
          value={this.state.value}
          onChange={this.handleChange}
        />
      </div>
    );
  }
}

useState()フックには初期値を与える

けれど、このクラスコンポーネントをフックで関数に改めたのが、冒頭のコンポーネントの定めです。処理の組み立てに違いがあるようには見えません。

ようやく判明したのが、フックuseState()に初期値を与えれば警告が消えるということです。クラスコンポーネントの例でstateの初期値に設定したのは空のオブジェクト{}ですから、ちょっと納得はいきません。少なくとも、警告メッセージにはもう少し情報がほしいところです。

// const [text, setText] = useState();
const [text, setText] = useState('');  // 初期値を与える

公開したCodeSandbox「React: Warning - Changing uncontrolled input with hook」は、src/index.jsがルートモジュールのsrc/App.jsを読み込んでいます。クラスコンポーネントsrc/App_class.jsと関数コンポーネントsrc/App_hook.jsのモジュールも別途加えました。それぞれをsrc/App.jsに差し替えて、結果の違いをお確かめください。

24
9
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
24
9