React.js&Next.js超入門 第2版で学習を進めていて、Chapter4の「簡易メモをつくる!」のサンプルコードでエラーが発生したので、解決方法を記しておきたいと思います。
私自身もReactをこちらの書籍で学習中の身ですがAmazonレビューでもサンプルコードが動かないことが指摘されており、困っている方もいるかと思うので記しておきます。
そのため、こちらの方法が最良の方法とは限らないことをご了承ください。
エラー発生箇所
エラーが発生している箇所はMemo.js
のsetMode('deafult')
の箇所が原因で
Error: Too many re-renders. React limits the number of renders to prevent an infinite loop.
エラーが発生します。
import React, { useState, useEffect } from 'react'
import usePersist from '../Persist'
import Item from './Item'
function Memo(props) {
const [memo, setMemo] = usePersist("memo", [])
const [fmemo, setFMemo] = usePersist("findMemo", [])
const [mode, setMode] = usePersist('mode', 'default')
let data = []
switch (mode){
case 'default':
data = memo.map((value,key)=>(
<Item key={value.message} value={value} index={key + 1} />
))
setMode('deafult') //←ここの処理が原因
break
case 'find':
data = fmemo.map((value,key)=>(
<Item key={value.message} value={value} index={key + 1}/>
))
break
default:
data = memo.map((value,key)=>(
<Item key={value.message} value={value} index={key + 1} />
))
}
return (
<table className="table mt-4">
<tbody>{data}</tbody>
</table>
)
}
export default Memo
解決方法
おそらくsetMode('deafult')
することでcase 'default'
内の処理が走り、またsetMode('deafult')
が走るというループが永遠に発生してしまうためにエラーが発生しまうのかと思います。
そのため、Memo.jsからsetMode('deafult')
を削除します。
import React, { useState, useEffect } from 'react'
import usePersist from '../Persist'
import Item from './Item'
function Memo(props) {
const [memo, setMemo] = usePersist("memo", [])
const [fmemo, setFMemo] = usePersist("findMemo", [])
const [mode, setMode] = usePersist('mode', 'default')
let data = []
switch (mode){
case 'default':
data = memo.map((value,key)=>(
<Item key={value.message} value={value} index={key + 1} />
))
// setMode('deafult') //←こちらを削除
break
case 'find':
data = fmemo.map((value,key)=>(
<Item key={value.message} value={value} index={key + 1}/>
))
break
default:
data = memo.map((value,key)=>(
<Item key={value.message} value={value} index={key + 1} />
))
}
return (
<table className="table mt-4">
<tbody>{data}</tbody>
</table>
)
}
export default Memo
しかし、Memo.js
からsetMode('deafult')
を削除してしまうと、mode
の値がfind
の場合にメモを追加しても追加した値を含むリストが表示されません。
そのためAddForm.js
にsetMode('deafult')
を追加します。
import React, { useState, useEffect } from 'react'
import usePersist from '../Persist'
function AddForm (props) {
const [memo, setMemo] = usePersist("memo", [])
const [message, setMessage] = useState('')
const [mode, setMode] = usePersist("mode", "default") //←こちらを追加
const doChange = (e)=> {
setMessage(e.target.value)
}
const doAction = (e)=> {
const data = {
message: message,
created: new Date()
}
memo.unshift(data)
setMemo(memo)
setMode("default") //←こちらを追加
setMessage('')
}
return (
<form onSubmit={doAction} action="">
<div className="form-group row">
<input type="text" className="form-control-sm col"
onChange={doChange} value={message} required />
<input type="submit" value="Add"
className="btn btn-primary btn-sm col-2" />
</div>
</form>
)
}
export default AddForm
またこちらはおまけですが、mode
の値がfind
の場合にメモを削除しても削除した値を除いたリストが表示されません。
そのためDelForm.js
にもsetMode("default")
を追加してあげると良いと思います。
import React, { useState, useEffect, memo } from 'react'
import usePersist from '../Persist'
function DelForm (props) {
const [memo, setMemo] = usePersist("memo", [])
const [num, setNum] = useState(0)
const [mode, setMode] = usePersist("mode", "default") //←こちらを追加
const doChange = (e)=> {
setNum(e.target.value)
}
const doAction = (e)=> {
let res = memo.filter((item, key)=> {
return key != num
})
setMemo(res)
setMode("default") //←こちらを追加
setNum(0)
}
let items = memo.map((value,key)=>(
<option key={key} value={key}>
{value.message.substring(0,10)}
</option>
))
return (
<form onSubmit={doAction}>
<div className="form-group row">
<select onChange={doChange} className="form-control-sm col"
defaultValue="-1" >
{items}
</select>
<input type="submit" value="Del"
className="btn btn-primary btn-sm col-2" />
</div>
</form>
)
}
export default DelForm
以上の修正で本来意図していたアプリの動作を再現することが出来ると思います。
少しでもこちらの書籍で学習されている方のお力になれれば幸いです。