【React】react-window を使用した写真ギャラリー

自分用のメモになります。最後に、写真ギャラリーを完成させたいと思います。

前回は以下を参照して下さい。

やりたいこと

表示するサムネイルにスタイルを当てたいと思います。
隣り合うサムネイルの間にボーダーを入れ、各サムネイルに間隔が空くように表示させます。

実装

Appコンポーネント

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 thumbnailLeftBorder = "5";

  // サムネイルのトップ間隔を決める。
  const thumbnailTopBorder = "3";

  // 写真(サムネイル)の表示
  const RenderItem = ({columnIndex, rowIndex, style, data}) => {

    // トップボーダーを設定する。
    let colBorder = {
      "border-top":  thumbnailTopBorder + "px solid #ffffff"
    };

    // 先頭行のトップボーダーは削除する。
    if(rowIndex === 0){
      delete colBorder["border-top"];
    }

    // 先頭列以外の場合、左ボーダーを設定する。
    const colNumber = columnIndex % columnCount;
    if(colNumber !== 0){
      colBorder["border-left"] = thumbnailLeftBorder + "px solid #ffffff";
    }

    return (
      <div style={{...style}}>
         <img src={data[rowIndex][columnIndex]} width={"100%"} style={colBorder}/>
      </div>
    );
  }

  return (
    <>
    <PhotoGallery 
      imgPathList = {imagePathList}
      renderItem = {RenderItem} 
      columnCount = {columnCount}
      tableWidth = {tableWidth}
      upDateList = {next}
      thumbnailLeftBorder = {Number(thumbnailLeftBorder)}
      // className = {className}
      />
    </>
  );
}

export default App;

dennie.css (任意なくてもOK)

前回と同じです。

.dennie_container {
    border: 4px solid red;
}

PhotoGalleryコンポーネント

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,  // サムネイルの縦の長さ(オプション)
  upDateList = f => f,     // サムネイルパス一覧更新関数(オプション)
  thumbnailLeftBorder = 0, // サムネイルの間隔。テーブルの長さに足す必要がある。
  className = 'container_center', // クラス名(オプション)
}) {

  // テーブルの高さ、幅を保持する。
  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 + thumbnailLeftBorder}
      rowCount = {imgPathList.length}
      rowHeight = {colHeight}
      itemData = {imgPathList}
      onScroll = {onScroll}
    >
      {renderItem}
    </FixedSizeGrid>
  );
}

export default PhotoGallery;

PhotoGallery.css

前回と同じです。

.container_center {
    margin: 0 auto;
}

ImgPathList フック

前回と同じです。

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;

最後に

特にありません。

コメントを残す

メールアドレスが公開されることはありません。

© DeNnie.Lab All Rights Reserved.