Kindle書籍「Next.jsでつくるフルスタックアプリ 後編 三好アキ著」を読んでの備忘録。
1.ステート変数宣言のシンプルな書き方
各データにつき一つのステートを用意するシンプルな書き方。
ここではname, email, そしてpasswordというステート変数を宣言している。
const Register = () => {
//↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ここ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
const [name, setName] = useState("")
const [email, setEmail] = useState("")
const [password, setPassword] = useState("")
//↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
const handleSubmit = async(e) => {
//(バックエンドに投げてユーザー登録する処理)
const response = await fetch("http://xxxx.com/user/reg",
{
method:"POST",
body: JSON.stringify({
name: name,
email: email,
password: password,
}),
})
}
return (
<div>
<form onSubmit={handleSubmit}>
<input value={name} onChange={(e) => setName(e.target.value)}
type="text" name="name" required />
<input value={email} onChange={(e) => setEmail(e.target.value)}
type="text" name="email" required />
<input value={password} onChange={(e) => setPassword(e.target.value)}
type="text" name="password" required />
<button>登録</button>
</form>
</div>
)
}
export default Register
ステート関数(setName()
やsetEmail()
)は、HTMLの<input>
タグにonChange={(e) =>setName(e.target.value)とインライン形式で指定され実行される。ありがちなパターン。
2.ステート変数を分割代入でまとめる書き方
次のように、各データ(ステート変数)をひとつのステート変数にまとめてしまう。ここではnewUser
にまとめている。
const Register = () => {
const [newUser, setNewUser] = useState({
name: "",
email: "",
password: "",
})
・・・省略・・・
こうした場合、まず関数を用意し(ここではhandleChange)、その中で次のようにステート変数のデータ書き込みを行う。
const Register = () => {
const [newUser, setNewUser] = useState({
name: "",
email: "",
password: "",
})
const handleChange = (e) => {
//↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ここ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
setNewUser({
...newUser,
[e.target.name]: e.target.value,
})
//↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
}
・・・省略・・・
ここで出てくるnewUserの前の点々...
が分割代入(Destructuring assignment)と呼ばれるらしい。
HTMLの<input>
タグのonChange=インラインはもちろんhandleChange関数に変更する。
また、この中で例えばemailにアクセスしたい場合はnewUser.email
となる。したがって、<input>
タグのvalue値も、例えばnameであったらnewUser.name
, emailであったらnewUser.email
と変更する。
const Register = () => {
const [newUser, setNewUser] = useState({
name: "",
email: "",
password: "",
})
const handleChange = (e) => {
setNewUser({
...newUser,
[e.target.name]: e.target.value,
})
const handleSubmit = async(e) => {
//(バックエンドにフェッチする処理)
const response = await fetch("http://xxxx.com/user/reg",
{
method:"POST",
body: JSON.stringify({
name: name,
email: email,
password: password,
}),
})
}
return (
<div>
<form onSubmit={handleSubmit}>
<input value={newUser.name} onChange={handleChange}
type="text" name="name" required />
<input value={newUser.email} onChange={handleChange}
type="text" name="email" required />
<input value={newUser.password} onChange={handleChange}
type="text" name="password" required />
<button>登録</button>
</form>
</div>
)
}
export default Register
こうすることで、複数の項目(nameやemail, password)を含んだnewUser
が出来上がる。
さて、バックエンドに送るべきデータはすべてステート変数newUser
に格納されているので、バックエンドにデータを投げる処理をするhandleSubmit関数の中の、データ記述部分(body
)も変更する。
これを
body: JSON.stringify({
name: name,
email: email,
password: password,
}),
})
このように変更
body: JSON.stringify(newUser)
完成形
const Register = () => {
const [newUser, setNewUser] = useState({
name: "",
email: "",
password: "",
})
const handleChange = (e) => {
setNewUser({
...newUser,
[e.target.name]: e.target.value,
})
const handleSubmit = async(e) => {
//(バックエンドにフェッチする処理)
const response = await fetch("http://xxxx.com/user/reg",
{
method:"POST",
body: JSON.stringify(newUser)
}
return (
<div>
<form onSubmit={handleSubmit}>
<input value={newUser.name} onChange={handleChange}
type="text" name="name" required />
<input value={newUser.email} onChange={handleChange}
type="text" name="email" required />
<input value={newUser.password} onChange={handleChange}
type="text" name="password" required />
<button>登録</button>
</form>
</div>
)
}
export default Register
3.あえてエラーを試してみる(この記事の肝)
setNewUser({
...newUser,
[e.target.name]: e.target.value,
})
なんとも不思議な書き方、こういうものだとスルーして良いのだが、いくつか意地悪を試してみる。
- 【疑問1】点々は3つでないとダメなのか?
【回答】
3つと決まっているようで、2つや4つにするとVS Codeが注意してくれる。
- 【疑問2】
[e.target.name]: e.target.value
と、e.target.nameにe.target.value
を割り当ててるコード部分がある。それを、[e.target.email]: e.target.value
のようにemailやpasswordにしてはダメなのか?
【回答】
ダメ。受け付けてくれない。ステート変数宣言部分をこのように順番を入れ替えてもダメ。
//分割代入
const [newUser, setNewUser] = useState({
email: "",
name: "",
password: "",
})
- 【疑問3】では、name, email共に二つ書いたり、name, email, password3つともすべて書くとどうなのか?
setNewUser({
...newUser,
[e.target.name]: e.target.value,
[e.target.email]: e.target.value,
[e.target.password]: e.target.value,
})
【回答】
これではせっかくひとつ(newUser
)にまとめた意味がないものの、受け付けてくれる。
- 【疑問4】入力フォームに「名前」(name)欄が無い場合はどうなのか? 当然ステート変数宣言は次のようなものになるが・・
const [newUser, setNewUser] = useState({
email: "",
password: "",
})
【回答】
この場合はさすがに[e.target.email]: e.target.value
であろうと推測した。しかしながら、実際はこの場合でものように[e.target.name]: e.target.value
とnameにしなければ受け付けてくれない。
setNewUser({
...newUser,
[e.target.name]: e.target.value,
})
4.残った疑問
結局、ここでの[e.target.name]
は何を指しているのだろうか。
もしかしたらスキーマであろうか? データベースに格納すべきデータのスキーマを次のように設定している(UserSchema
)。しかし、これはバックエンドプログラムがMongoDBにデータを書き込むために用意された物。フロントでは使っていない。
//utils/ShemaModels.js
const UserSchema = new Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true,
unique: true
},
password: {
type: String,
required: true,
}
})
やはり、不明のままである。
本の宣伝
Gatsbyバージョン4>>>>改訂新版
前編の『Gatsby4+Tailwind+Gatsby Cloudでつくる~』と後編の『JAMStackを学ぼうGatsby4+microCMSでつくる~』を合わせ、次のようなデモサイトを構築します。
→ https://yah-space.work
静的サイトジェネレーターGatsbyの基本とnode APIの扱いについて踏み込んだ解説書。またバージョン4の新機能《DSG(静的サイトジェネレーション》と《Gatsby Functions》での問い合わせフォーム実装、Tailwind CSSでのレイアウト、Gatsbyと相性が良いGatsby Cloudを紹介し解説しております。
JAMStackを学ぼう Gatsby4+Tailwind CSS+Gatsby Cloudでつくるコーポレートサイト ~もうレンタルサーバーはいらない~ 改訂新版 前編(書籍2,980円)
GatsbyとmicroCMSを組み合わせてのコーポレートサイト作成手順を解説・ハンズオンした続編。待望の《サイト内検索機能》を《Gatsby Functions》と《microCMSのqパラメータ》で実装。
JAMStackを学ぼう Gatsby4+microCMSでつくるコーポレートサイト ~WordPressはもう古い~ 改訂新版 後編(書籍 2,580円)