掌田津耶乃 React.js&Next.js超入門 第2版で学習を進めていていますが、サンプルコードでいくつかバグやミスがあるのでまとめます。
4-6 簡易メモ
React.js&Next.js超入門 第2版の簡易メモのバグ修正
参照
5-3 fetch APIでJSONデータにアクセスする
React.js&Next.js超入門 第2版の無限ループのバグ修正
参照
5-3 SWRを利用する
デフォルトのfetcherはもうない
319pから使っているuseSWRについて、最近swr
がv1にアップデートされ、上記のようにデフォルトのfetcher
がなくなりました。このためswr
のV1.0以降インストールすると、この書籍のswr
関連のコードはうまく動きません。
解決策として、
const fetcher = (...args) => fetch(...args).then(res => res.json())
export default function Home(){
const{data}=useSWR('/data.json',fetcher)
...
とjson
をパースするようなfetcherを自分で作り、useSWR
の第2引数に指定するか、swr
をインストールする際に
npm install swr@0.5.6
と古いバージョンを指定してインストールするようにしてください。
useSWR
使用上のミス
これはバグではなくミスですが、useSWR
の2つ目の返り値をerrとしていますが、useSWRの返り値はオブジェクトで、プロパティ名はdataとerrorで固定なので、正しくはこうです。
const { data,error}= useSWR(/data.txt,func)
どうしてもerrという変数名にしたい場合は次のようにします。
const { data,error:err}= useSWR(/data.txt,func)
なぜこうなるかについては、331pで返り値がオブジェクトのときの分割代入の説明をしているので、その説明が参考になると思います。
もしくはJavaScriptのオブジェクトの分割代入について調べると参考になると思います。
ただ、このコードではerrを使っていないので、このミスはエラーになっていないです。
5-4 プログラマブル電卓
5-4のプログラマブル電卓にもバグがあります。
343pのCalc.jsの中ほど、doFunc()
関数内で
const fe = eval(f.function)
const res = fe(arr)
となっていますがこのままだと関数に配列がそのまま渡されてしまいます。次のようにスプレッド構文で配列を展開して渡さないといけません。
const fe = eval(f.function)
const res = fe(...arr)
コード改善
またこれは余談ですが、せっかく前の節でuseSWR
を学んだのに、このプログラマブル電卓では使っていません
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
を使えばよりシンプルになります。
// 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
つい最近(2021/9/1)firebaseのJavaScript SDKのバージョンがアップデートされ、v8→v9になったようです。それに伴い、コードの互換性が失われています。
この書籍はv8で書かれているので、
# npm install firebase@8.9.1
とv8をインストールするようにするか、もしくは
import firebase from 'firebase/compat/app';
import
するときにcompat
をつけると、今まで通りv8として使えるようです。詳しくは上記記事を参照してください。
また、@sgigagaeruさんがこの本のFirebaseコードをv9で動くようにリファクタリングされています。
6-5 メッセージが送れるアドレスブック
これもバグではなく、仕様かもしれないです。
アドレスデータとメッセージを表示するinfo.js
について、p425で
《ログインユーザー側の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ページでメッセージをやり取りするアカウントそれぞれでお互いのデータをアドレス帳に登録してから使うようにすればエラーは出ません。
以上
以上です。余裕があれば順次更新していきたいです。