LoginSignup
15
14

More than 3 years have passed since last update.

React Hooks useStateでformのonChangeハンドリング

Last updated at Posted at 2020-06-14

React Hooksでフォームで全てのinput要素にonChangeイベントを割り当てる際、input要素が多いと大変面倒くさいと感じていたので。

  • Reactには一月前から触れたばかりで日々学習しています。
  • 公式チュートリアル、ドキュメントを一通りやって、オリジナルアプリの開発を始めた段階です。
  • 公式がこれからはHooksで行くと暗に宣言していると感じたので、クラスコンポーネントは流しただけです。最初からHooksオンリーで始めています。
  • JavaScriptはなんとなくやっている感じで体系的な学習はまだまだです。

Reactでフォームを扱う場合

自分はform要素を一つ一つstateにして、onChangeイベントでは条件分岐でtargetのname属性に応じて該当するstateを割り当てていました。

form.jsx
const Form = (props) => {
    //input要素を一つ一つstateとしていた。input要素が増えると面倒
    const [firstName, setFirstName] = useState(null);
    const [lastName, setLastName] = useState(null);
    const [email, setEmail] = useState(null);

  //name属性でstate名を判断する条件分岐 
    const handleChange = (e) => {
        if(e.target.name === 'firstname') {
            setFirstName (e.targetValue);
        } else if (e.target.name === 'lastname') {
            setLastName (e.targetValue);
        } else if (e.target.name === 'email') {
            setEmail (e.targetValue);
        }
    }

    const handleSubmit = (e) => {
        // do something
    }

    return (
    <form onSubmit={this.handleSubmit}>
        <input type="text" name="firstname" value={firstName} onChange={handleChange} />
        <input type="text" name="lastname" value={lastName} onChange={handleChange} />
        <input type="text" name="email" value={email} onChange={handleChange} />
        <input type="submit" value="Submit" />
    </form>
    )
 }

なんかもの凄く無駄な記述をしているような気がしていました。でもReactではform要素もReactの支配下で管理するというスタンスなので、こうせざるを得ないのかなと思っていたのです。
それにstateを逐一監視していなくてもsubmitの段階で確定してくれればそれでいいと思うのですが、そうやろうとするとinput要素は入力を受け付けてくれません。useRefも試してみましたが、余計面倒になり諦めました。
このform要素をまとめてオブジェクトとして扱おうとすると、ちょっと扱いが面倒という記事もチラホラ目にしましたし。

海外YouTuberのReact解説を風呂でボケーっと眺めていて、以下のような記述ができると知って早速拝借。
(この方はクラスコンポーネントで記述していましたが)。

form.jsx
const Form = (props) => {
   //formステートをオブジェクトにしてinput要素はプロパティで設定
    const [form, setForm] = useState({firstName: '', lastName: '', email: ''});
  
   //これでonChangeイベントを動的に扱えるので条件分岐不要
    const handleChange = (input) => e => {
        setForm({...form, [input] : e.target.value});
    };

    const handleSubmit = (e) => {
        // do something
    }

    return (
    <form onSubmit={handleSubmit}>
        <input type="text" value={firstName} onChange={handleChange('firstName')} />
        <input type="text" value={lastName} onChange={handleChange('lastName')} />
        <input type="text" value={email} onChange={handleChange('email')} />
        <input type="submit" value="Submit" />
    </form>
    )
 }

formというstateをオブジェクトにしてinput要素をプロパティで持たせて、
handleChangeの引数にstateオブジェクトのプロパティ名を渡すだけでスッキリしました。

handleChangeのアロー関数のアローが二つ出てくるのですが、一つにすると、

form.jsx
const handleChange = (input) => {
        return e => setForm({...form, [input]: e.target.value})
    }

こういう意味らしい。
それと、setForm({[input]: e.target.value})とついついやってしまうのですが、
React Hooksのstateの変更はマージではなくて置換ですので({...form, [input]: e.target.value})ですね。

こちらの方の記事にもこの扱いが出ていました。やはり最初は面倒だなと思いますよねこれ。こちらの方の記事の方がわかりやすいです。
参考記事:React Hooks での form の扱い方

これでやっとフォームコンポーネント作るの億劫でなくなりました。

15
14
0

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
15
14