🎮

【React】Warning: A component is changing an uncontrolled ...について調べてみた

2023/01/06に公開

はじめに

はじめまして👋
バヅクリ株式会社 のエンジニア、伊藤と申します。
主にフロントエンド部分を担当しています。

この記事を書いた背景

弊社ではNext.jsを使用したサービス開発を行っています。
入力フォームを実装していた際に起こった、Reactの警告について調べたことをアウトプットする目的でこの記事を書きました。

警告内容と警告が出る例

警告内容

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

入力値を制御するのか、しないのかどちらかにしてください

という内容です。

警告が出る例

実際に警告が出る状況の例です↓
入力値をuseStateで管理していてchangeイベント毎にstateの値が更新されています。

import { TextField } from "@mui/material";
import { useState } from "react";

export default function App() {
  const [name, setName] = useState();
  return (
    <form>
      <TextField
        id="outlined-basic"
        label="Outlined"
        variant="outlined"
        value={name}
        onChange={(target) => setName(target.value)}
      />
    </form>
  );
}

解決した方法

stateに初期値を設定することで、controlled componentと認識され解決しました!

import { TextField } from "@mui/material";
import { useState } from "react";

export default function App() {
+ const [name, setName] = useState("");
  return (
    <form>
      <TextField
        id="outlined-basic"
        label="Outlined"
        variant="outlined"
        value={name}
        onChange={(target) => setName(target.value)}
      />
    </form>
  );
}

controlled、uncontrolledとは

コンポーネント内でinputした値を扱う方法は2種類あります。

  • controlled component(制御コンポーネント)
    stateを使用して扱う。各値の更新にはsetStateを使用する。

  • uncontrolled component(非制御コンポーネント)
    DOM自身で扱い、値へのアクセスはRefを使用する。

controlled componentはフォーム要素が増えるとstateも増え、
更新毎で再レンダリングが起きることで、パフォーマンス面が落ちることがあります。
その点、uncontrolled componentの場合は再レンダリングのコストは軽減すると思いました。

React Hook Form

弊社ではフォームバリデーションライブラリにReact Hook Formを使用しています。ドキュメントにパフォーマンス関する記載がありました。

Performance of React Hook Form
Performance is one of the primary reasons why this library was created. React Hook Form relies on an uncontrolled form, which is the reason why the register function captures ref and the controlled component has its re-rendering scope with Controller or useController. This approach reduces the amount of re-rendering that occurs due to a user typing in an input or other form values changing at the root of your form or applications. Components mount to the page faster than controlled components because they have less overhead. As a reference, there is a quick comparison test that you can refer to at this repo link.

https://react-hook-form.com/faqs

  • React Hook Formではcontrolled/uncontrolledのどちらでも実装は可能で、基本的にはregister関数を使用してuncontrolledなフォームに依存している。

  • ControllerまたはuseControllerを使用すると、controlledなフォームを実装できる。また、スコープを持つため再レンダリングの負荷を減らすことができる。

React Hook Formがパフォーマンスを売りにしている理由はここにあったんですね📝(急な感想)

それぞれのUseCaseを考える

Reactのドキュメントでは以下のようにありました。

ほとんどの場合では、フォームの実装には制御されたコンポーネント (controlled component) を使用することをお勧めしています。
https://ja.reactjs.org/docs/uncontrolled-components.html

が、どちらにもメリットデメリットは存在し、使用用途やプロジェクトの方針によって選択することが大切だと思いました。

下記サイトにはそれぞれの比較が表になっていて分かり易かったです!
https://goshacmd.com/controlled-vs-uncontrolled-inputs-react/

最後に

バヅクリではエンジニアを募集しています!
カジュアル面談等も受け付けておりますので、ご興味ある方は下記リンクから是非お問い合わせください。

https://herp.careers/v1/buzzkuri/wCQFGVkQS3Xa

https://buzzkuri.co.jp/recruit

バヅクリテックブログ

Discussion