#React Hooksでフォームで全てのinput要素にonChangeイベントを割り当てる際、input要素が多いと大変面倒くさいと感じていたので。
- Reactには一月前から触れたばかりで日々学習しています。
- 公式チュートリアル、ドキュメントを一通りやって、オリジナルアプリの開発を始めた段階です。
- 公式がこれからはHooksで行くと暗に宣言していると感じたので、クラスコンポーネントは流しただけです。最初からHooksオンリーで始めています。
- JavaScriptはなんとなくやっている感じで体系的な学習はまだまだです。
##Reactでフォームを扱う場合
自分はform要素を一つ一つstateにして、onChangeイベントでは条件分岐でtargetのname属性に応じて該当するstateを割り当てていました。
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解説を風呂でボケーっと眺めていて、以下のような記述ができると知って早速拝借。
(この方はクラスコンポーネントで記述していましたが)。
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のアロー関数のアローが二つ出てくるのですが、一つにすると、
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 の扱い方
これでやっとフォームコンポーネント作るの億劫でなくなりました。