LoginSignup
12
1

More than 1 year has passed since last update.

React.js&Next.js超入門 第2版の簡易メモのバグ修正

Last updated at Posted at 2021-07-12

React.js&Next.js超入門 第2版で学習を進めていて、Chapter4の「簡易メモをつくる!」のサンプルコードでエラーが発生したので、解決方法を記しておきたいと思います。

私自身もReactをこちらの書籍で学習中の身ですがAmazonレビューでもサンプルコードが動かないことが指摘されており、困っている方もいるかと思うので記しておきます。 そのため、こちらの方法が最良の方法とは限らないことをご了承ください。

エラー発生箇所

エラーが発生している箇所はMemo.jssetMode('deafult')の箇所が原因で
Error: Too many re-renders. React limits the number of renders to prevent an infinite loop.エラーが発生します。

Memo.js
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')を削除します。

Memo.js
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.jssetMode('deafult')を追加します。

AddForm.js
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")を追加してあげると良いと思います。

DelForm.js
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

以上の修正で本来意図していたアプリの動作を再現することが出来ると思います。
少しでもこちらの書籍で学習されている方のお力になれれば幸いです。

12
1
1

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
12
1