React.js&Next.js超入門 第2版 サンプルコードのバグまとめ


[掌田津耶乃　React.js&Next.js超入門 第2版](https://www.shuwasystem.co.jp/book/9784798063980.html)で学習を進めていていますが、サンプルコードでいくつかバグやミスがあるのでまとめます。


# 4-6 簡易メモ

[React.js&Next.js超入門 第2版の簡易メモのバグ修正](https://qiita.com/kmat/items/01addf420839cb1089bc)

参照

# 5-3 fetch APIでJSONデータにアクセスする

[React.js&Next.js超入門 第2版の無限ループのバグ修正](https://qiita.com/SolKul/items/20e178a76b68af5c66bf)

参照

# 5-3 SWRを利用する

## デフォルトのfetcherはもうない

https://swr.vercel.app/blog/swr-v1#no-more-default-fetcher

319pから使っているuseSWRについて、最近`swr`がv1にアップデートされ、上記のようにデフォルトの`fetcher`がなくなりました。このため`swr`のV1.0以降インストールすると、この書籍の`swr`関連のコードはうまく動きません。

解決策として、

```js
const fetcher = (...args) => fetch(...args).then(res => res.json())

export default function Home(){
  const{data}=useSWR('/data.json',fetcher)
  ...
```

と`json`をパースするようなfetcherを自分で作り、`useSWR`の第2引数に指定するか、`swr`をインストールする際に

```bash
npm install swr@0.5.6
```
と古いバージョンを指定してインストールするようにしてください。

## `useSWR`使用上のミス

これはバグではなくミスですが、`useSWR`の2つ目の返り値をerrとしていますが、useSWRの返り値はオブジェクトで、プロパティ名はdataとerrorで固定なので、正しくはこうです。

```js
const { data,error}= useSWR(/data.txt,func)
```

どうしてもerrという変数名にしたい場合は次のようにします。

```js
const { data,error:err}= useSWR(/data.txt,func)
```

なぜこうなるかについては、331pで返り値がオブジェクトのときの分割代入の説明をしているので、その説明が参考になると思います。
もしくはJavaScriptのオブジェクトの分割代入について調べると参考になると思います。

ただ、このコードではerrを使っていないので、このミスはエラーになっていないです。

# 5-4 プログラマブル電卓

5-4のプログラマブル電卓にもバグがあります。
343pのCalc.jsの中ほど、`doFunc()`関数内で

```Calc.js
    const fe = eval(f.function)
    const res = fe(arr)
```
となっていますがこのままだと関数に配列がそのまま渡されてしまいます。次のようにスプレッド構文で配列を展開して渡さないといけません。

```Calc.js
    const fe = eval(f.function)
    const res = fe(...arr)
```


## コード改善

またこれは余談ですが、せっかく前の節で`useSWR`を学んだのに、このプログラマブル電卓では使っていません

```Calc.js
export default function Calc(props) {
  const [message, setMessage] = useState('')
  const [input, setInput] = useState('')
  const [data, setData] = usePersist('calc-history', [])
  const [func, setFunc] = useState({func:{}})

  const fetchFunc = (address)=> 
    fetch(address).then(res => res.json())
  
  useEffect(() => {
    fetchFunc('/api/func').then((r)=>{
      setFunc(r)
    })
  },[data])

...略

```

このコードを次のように`useSWR`を使えばよりシンプルになります。

```Calc.js
// fetcherを用意
const fetcher = (...args) => fetch(...args).then(res => res.json())

export default function Calc(props){
  const [message, setMessage]=useState('')
  const [input,setInput]=useState('');
  const [data,setData]=usePersist('calc-history',[])

  //書籍のコードをコメントアウト
  // const [func, setFunc] = useState({func:{}})

  // const fetchFunc = (address)=> 
  //   fetch(address).then(res => res.json())
  
  // useEffect(() => {
  //   fetchFunc('/api/func').then((r)=>{
  //     setFunc(r)
  //   })
  // },[data])

  //代わりのコード
  const { data:func,error }=useSWR('/api/func',fetcher) 
  // 関数のJSONデータ読み込みがエラーになった時とデータ読み込み中の時の表示
  if (error) return <div className="alert alert-primary text-center">failed to load</div>
  if (!func) return <div className="alert alert-primary text-center">loading...</div>

...略

```

データ読み込み中は、`func`が`undefined`になっています。この時に`func`のプロパティにアクセスしようとするなど、`func`関連の処理をしようとすると`500 internal server error`となってしまうので、`func`が`undefined`の場合は`func`関連の処理をする前に、読み込み中であるという表示を返しておけばいいです

# 6章 Firebase

https://qiita.com/hirochan/items/68fc374715c30c5a02fa

つい最近(2021/9/1)firebaseのJavaScript SDKのバージョンがアップデートされ、v8→v9になったようです。それに伴い、コードの互換性が失われています。

この書籍はv8で書かれているので、

```shell-session
# npm install firebase@8.9.1
```

とv8をインストールするようにするか、もしくは

```javascript
import firebase from 'firebase/compat/app';
```

`import`するときに`compat`をつけると、今まで通りv8として使えるようです。詳しくは上記記事を参照してください。

また、[@sgigagaeru](https://qiita.com/sgigagaeru)さんがこの本のFirebaseコードをv9で動くようにリファクタリングされています。

https://qiita.com/sgigagaeru/items/f61f7b90dc0ad46b3565

# 6-5 メッセージが送れるアドレスブック

これもバグではなく、仕様かもしれないです。

アドレスデータとメッセージを表示する`info.js`について、p425で

```info.js
《ログインユーザー側のmessageコレクション》.add(to).then(ref=>{
  《送信先アカウントのmessageコレクション》.add(from).then(ref=>{
    《送信先アカウントのドキュメント》.update({flag:true}).then(ref=>{
      ...リダイレクト...
    })
  })
})
```

と、メッセージを追加した後、新着メッセージのフラグを`update({flag:true})`として`true`に更新しています。しかしこれは送信先アカウントのアドレス帳のログインユーザー側のアドレス情報(具体的にはfirestoreの`db.collection('address').doc(router.query.id).collection('address').doc(auth.currentUser.email)`)に`flag`フィールドが存在していない場合、エラーになります。

簡単に言えば、お互いのデータがアドレス帳に登録されていないとこのメッセージアプリは使えないということです。

ただ、このエラーを回避しようとすると、コードが複雑なるのであえてこうしていると思われます。

このメッセージアプリのinfoページでメッセージを送る前に、addページでメッセージをやり取りするアカウントそれぞれでお互いのデータをアドレス帳に登録してから使うようにすればエラーは出ません。

# 以上

以上です。余裕があれば順次更新していきたいです。