はじめに
コーディング学習の一環として、簡単な学習記録記録アプリを作成した。
入力した記録をリストアップすることができ、学習時間の合計も算出される。

問題
学習記録については、以下のようなオブジェクト配列のStateで管理している。
const [records,setRecords] = useState([{title:"記録1",time:2},{title:"記録2",time:1}])
学習時間の合計を算出する際、はじめはreduce関数で以下のように記述した。
records.reduce((a,b)=>{a.time + b.time})
しかし、これを実行したところ、配列の要素数が1のときは返り値がオブジェクトになり、要素数が3以上のときはNaNが返却され、意図したような動作にならなかった。
解決方法
list.reduceの処理について詳しく知らないまま使っていたのが原因だった。
調べたところ、以下のような処理であった。
records.reduce((a,b)=>{a + b})
上記関数の実行時、変数aとbには初期値として以下が渡される。
a = 配列の第一要素, b=配列の第二要素
そして、アロー関数を実行した後、その結果はaに格納され、 次の配列要素で同じような処理を行う。
この時、変数aとbの中身は以下のようになる。
a = 前回のアロー関数の実行結果(配列の第一要素,第二要素の合計), b = 配列の第三要素
これを踏まえて、問題の関数を見てみると、次のような動作が行われるとわかる。
records.reduce((a,b)=>{a.time + b.time})
- 配列の要素数が1の場合
- aの初期値は、records配列の第一要素(title,timeを持つオブジェクト)となる。 そして、配列に要素が1つしかない場合、reduce関数はアロー関数を無視し、第一要素をそのまま返却するため、結果はオブジェクトになる。
- 配列の要素数が2の場合
- 配列の第一要素と第二要素のそれぞれのtimeを足し合わせた値が返却される。これが唯一まともに動作する場合である。
- 配列の要素数が3の場合
- 1度目の処理で時間が正常に足し合わされた後、2度目の処理ではaの値はtimeの合計の数値となり、オブジェクトではなくなる。 そのため、a.timeは存在せず、結果はNaNとなる。
結果として、recordsからmap関数でtimeだけを数値配列として抽出し、その後reduce関数で足し合わせることで、正常に動作した。
records.map((v) => v.time).reduce((a, b) => a + b)
おわりに
関数や機能をよくわからないまま使うと、ちょっとしたことでつまづいてしまうため、事前によく調べてから使うべきだと感じた。最近ではAIもあるため、AIに聞くなどするのもアリだと思う。
参考
JISOUのメンバー募集中!
プログラミングコーチングJISOUでは、新たなメンバーを募集しています。
日本一のアウトプットコミュニティでキャリアアップしませんか?
興味のある方は、ぜひホームページをのぞいてみてくださ!
▼▼▼