はじめに
この記事は、MUI が提供している usePagination というカスタムフックのコードリーディング第三回です。
前回、前々回の記事をまだご覧になっていない方は、そちらも併せてご覧ください。
前回は、usePagination フックを実際に使ってみました。
そしてその戻り値から、総件数と現在ページを渡すだけで、いい感じに省略表示したページの配列を返してくれるということがわかりました。
今回は、その配列を作るための処理をコードリーディングしてみたいと思います。
概要
以下は、ページの配列を作っている箇所を抜粋したコードです。
大きく二つに分けることができます。
前半はページの配列を部分ごとに作る処理、後半はそれらを結合する処理です。
const range = (start, end) => {
const length = end - start + 1;
return Array.from({ length }, (_, i) => start + i);
};
const startPages = range(1, Math.min(boundaryCount, count));
const endPages = range(Math.max(count - boundaryCount + 1, boundaryCount + 1), count);
const siblingsStart = Math.max(
Math.min(
// Natural start
page - siblingCount,
// Lower boundary when page is high
count - boundaryCount - siblingCount * 2 - 1,
),
// Greater than startPages
boundaryCount + 2,
);
const siblingsEnd = Math.min(
Math.max(
// Natural end
page + siblingCount,
// Upper boundary when page is low
boundaryCount + siblingCount * 2 + 2,
),
// Less than endPages
count - boundaryCount - 1,
);
// Basic list of items to render
// for example itemList = ['first', 'previous', 1, 'ellipsis', 4, 5, 6, 'ellipsis', 10, 'next', 'last']
const itemList = [
...(showFirstButton ? ['first'] : []),
...(hidePrevButton ? [] : ['previous']),
...startPages,
// Start ellipsis
// eslint-disable-next-line no-nested-ternary
...(siblingsStart > boundaryCount + 2
? ['start-ellipsis']
: boundaryCount + 1 < count - boundaryCount
? [boundaryCount + 1]
: []),
// Sibling pages
...range(siblingsStart, siblingsEnd),
// End ellipsis
// eslint-disable-next-line no-nested-ternary
...(siblingsEnd < count - boundaryCount - 1
? ['end-ellipsis']
: count - boundaryCount > boundaryCount
? [count - boundaryCount]
: []),
...endPages,
...(hideNextButton ? [] : ['next']),
...(showLastButton ? ['last'] : []),
];
一つずつ見ていきましょう。
部分ごとの解説
連番を作成する関数 range
ページャのボタンは、連続している箇所は必ず連番になります。
この処理は、その連番部分を作成します。
引数のstart
と end
の値から連番の範囲 length
を求めます。
そして、その範囲の分だけ連番の配列を作成します。
const range = (start, end) => {
const length = end - start + 1;
return Array.from({ length }, (_, i) => start + i);
};
例として、start=1
end=3
を渡した場合、以下のような出力になります。
console.log(range(1, 3))
// [1, 2, 3]
始めのページと終わりのページ
const startPages = range(1, Math.min(boundaryCount, count));
const endPages = range(Math.max(count - boundaryCount + 1, boundaryCount + 1), count);
いきなりややこしいですが、ひるまず一つずつ見ていきましょう。
startPages
は、1から boundaryCount
か count
の小さい方までの連番となります。
例えば、boundaryCount
が 1 で、count
が 3 のとき、range(1, 1)
となり、出力は [ 1 ]
となります。
同様に、boundaryCount
が 2 で、count
が 3 のとき、range(1, 2)
となり、出力は [ 1, 2 ]
となります。
もう一つ見てみましょう。boundaryCount
が 5 で、count
が 10 のとき、range(1, 5)
となり、出力は [ 1, 2, 3, 4, 5 ]
となります。
最後です。boundaryCount
が 5 で、count
が 2 のとき、range(1, 2)
となり、出力は [ 1, 2 ]
となります。
この結果から startPages
は、1から boundaryCount
までの範囲、ただし boundaryCount
が count
を超える場合は count
までの範囲となることがわかります。
続いて、endPages
です。startPages
よりさらにややこしいですね。
先ほどのように、実際に値を当てはめて確認していきましょう。
例えば、boundaryCount
が 1 で、count
が 10 のとき、range(10, 10)
となり、出力は [ 10 ]
となります。
同様に、boundaryCount
が 2 で、count
が 5 のとき、range(4, 5)
となり、出力は [ 4, 5 ]
となります。
もう一つ見てみましょう。boundaryCount
が 5 で、count
が 10 のとき、range(6, 10)
となり、出力は [ 6, 7, 8, 9, 10 ]
となります。
最後です。boundaryCount
が 5 で、count
が 2 のとき、range(6, 2)
となり、出力は []
となります。
この結果から endPages
は、count - boundaryCount + 1
から count
までの範囲、ただし count
がある一定より少ない場合は boundaryCount + 1
までの範囲となることがわかります。
さらに、最後の例にあるとおり、場合によっては空配列となる場合もあります。
これらの結果からboundaryCount
は「ページャの両端からボタンを表示する数」だと考えてよさそうですね。
そして、boundaryCount
に大きな値が渡された場合の考慮もされていることがわかりました。
おわりに
いかがだったでしょうか?
第1回の記事で、boundary=境界なのでboundaryCount
は省略表示に関係しているのでは?と予想していました。
答え合わせとしては「両端から省略記号まで表示する数」でしたね。
次回も残りの処理を紐解いていきましょう。
第1回の記事で想像するのも難しかった siblingCount
が登場します。
コメント