前回は固定数のデータ(jsonから読み込んがサムネイルパス一覧)をテーブルに表示させていました。
前回は以下を参照して下さい。
今回は、テーブルをスクロールしてスクロールがボトムまで行きそうになったら、サムネイルパス一覧を更新し、表示できるサムネイルの数を動的に増やします。
目次
実装
Appコンポーネント
サムネイルパス一覧が jsonデータからではなく ImgPathList フックの返却値の第一引数 imagePathList から取得できます。第二引数は、サムネイルパス一覧を更新する関数(next)になります。next関数をPhotoGalleryコンポーネントのupDateListプロパティへ渡しています。PhotoGalleryコンポーネントでスクロールの判定を行い、upDateListプロパティで受け取ったサムネイルパス一覧を更新する関数(next)を実行する為です。
import './App.css';
// import './dennie.css';
import React from 'react';
import PhotoGallery from './PhotoGallery';
import ImgPathList from './ImgPathList';
function App() {
// 列の数(1列に表示する写真の数)
const columnCount = 4;
// テーブルの幅(0〜1で設定する。ex)0.8 は幅80%)
const tableWidth = 0.8;
// クラス名(オプション)
// const className = "dennie_container";
// 第一引数がサムネイルパス一覧。第二引数はサムネイルパス一覧を更新する関数。
const [imagePathList, next] = ImgPathList(columnCount);
// 写真(サムネイル)の表示
const RenderItem = ({columnIndex, rowIndex, style, data}) => {
return (
<div style={{...style}}>
<img src={data[rowIndex][columnIndex]} width={"100%"}/>
</div>
);
}
return (
<>
<PhotoGallery
imgPathList = {imagePathList}
renderItem = {RenderItem}
columnCount = {columnCount}
tableWidth = {tableWidth}
upDateList = {next}
// className = {className}
/>
</>
);
}
export default App;
dennie.css (任意なくてもOK)
前回と同じです。
.dennie_container {
border: 4px solid red;
}
PhotoGalleryコンポーネント
サムネイルパス一覧を更新する関数を受け取ります。FixedSizeGrid に onScroll プロパティを指定することで、スクロールすると実行されるイベントを登録できます。
import './PhotoGallery.css';
import React, { useLayoutEffect , useState} from 'react';
import {FixedSizeGrid} from 'react-window';
function PhotoGallery({
imgPathList = [], // サムネイルパス一覧
renderItem, // カラム表示
columnCount, // カラム数
tableWidth = 1, // テーブルの幅(1で横幅マックス)(オプション)
orgItemSizeWith = 1, // サムネイルの横の長さ(オプション)
orgItemSizeHigt = 1, // サムネイルの縦の長さ(オプション)
className = 'container_center', // クラス名(オプション)
upDateList = f => f, // サムネイルパス一覧更新関数(オプション)
}) {
// テーブルの高さ、幅を保持する。
const [width, setWidth] = useState(0);
const [height, setHeight] = useState(0);
// テーブルの高さ、幅をリサイズする。
const resize = () => {
setWidth(window.innerWidth);
setHeight(window.innerHeight);
}
useLayoutEffect(() => {
window.addEventListener("resize", resize);
resize();
},[])
// 列の幅
let colWidth = (width * tableWidth) / columnCount;
// 列の高さ(行の高さ) 列の幅 * 縦横比率
let colHeight = colWidth * (orgItemSizeHigt / orgItemSizeWith);
// データリストの高さ
let listHeight = colHeight * imgPathList.length;
// スクロールイベント。スクロール位置とデータリストの高さを判定して、ボトムになりそうな場合、サムネイルパス一覧を更新する。
const onScroll = ({
scrollTop,
}) => {
if(scrollTop > listHeight - 1000){
upDateList();
}
}
return (
<FixedSizeGrid
className = {className}
columnCount = {columnCount}
columnWidth = {colWidth}
height = {height}
width = {width * tableWidth}
rowCount = {imgPathList.length}
rowHeight = {colHeight}
itemData = {imgPathList}
onScroll = {onScroll}
>
{renderItem}
</FixedSizeGrid>
);
}
export default PhotoGallery;
PhotoGallery.css
前回と同じです。
.container_center {
margin: 0 auto;
}
ImgPathList フック
今回新しく追加しました。imagePathList はサムネイルパス一覧になります。next はサムネイルパス一覧を更新する関数になります。
import {useState} from 'react';
function ImgPathList(columnCount = 5, parListCount = 10) {
// 現在のパス名のカウント
const [currentNumber, setCurrentNumber] = useState(1014659);
// サムネイルパス一覧
const [imagePathList, setImagePathList] = useState([]);
const next = () => {
// 新たにサムネイルパス一覧を生成する。
let cnt = 0;
let imgPathList = [...Array(parListCount)].map(element => {
return [...Array(columnCount)].map(elem => {
const strCurrentNumber = String(currentNumber + cnt);
const imagePath = `https://dennie.tokyo/norway/img/photos/square/P${strCurrentNumber}.jpg`;
cnt++;
return imagePath;
});
});
// 現在のパス名のカウントを増えた分更新する。
setCurrentNumber(currentNumber + cnt - 1);
// サムネイルパス一覧を更新する。
setImagePathList(imagePathList.concat(imgPathList));
}
return [imagePathList, next];
}
export default ImgPathList;
最後に
最後に写真ギャラリーとして完成させます。