【Next.js】Next.js + useSWR + Material-uiでPagiNationを実現

はじめに

こんにちは、がんがんです。
前回のNext.js関連の記事にて、データをキャッシュすることが出来るSWRについて備忘録を書きました。
gangannikki.hatenadiary.jp


今回は、前回記事の最後で触れているuseSWR + PagiNationに関する備忘録を書いておきます。
今まであったuseSWRPagesは廃止されたようなので、今後の自分のためにも備忘録をまとめておきます。


f:id:gangannikki:20200907200026j:plain

公式ドキュメント

新しいライブラリに関しては参考記事がないので公式ドキュメントを参考にしていきます。
swr.vercel.app

参考記事(仕様変更で現在は使えないもの)

SWRライブラリの更新により、現在のバージョンではuseSWRPagesが廃止されました。
そのため、下記の記事は使えませんが参考としてまとめておきます。

Please update to the latest version (≥ 0.3.0) to use this API. The previous useSWRPages API is now deprecated.

「zeit/swr」のpagination exampleでScroll Position Restoreを試す - Qiita

useSWRPages Pagination – the2g

インストール

前回の記事でインストールなどは済ませているので割愛します。こちらを参照ください。
gangannikki.hatenadiary.jp

環境

  • Next.js
  • Material-ui
  • swr


フロント部分

まずはフロント部分を用意します。

/pages/TestPage.js
import React, { useState } from 'react';
import Container from '@material-ui/core/Container';
import Grid from '@material-ui/core/Grid';
import { makeStyles } from '@material-ui/core/styles';
import Pagination from '@material-ui/lab/Pagination';
import CardArea from '../components/CardArea';

const useStyles = makeStyles((theme) => ({
  cardGrid: {
    paddingTop: theme.spacing(8),
    paddingBottom: theme.spacing(8),
  },
  pageNation: {
    paddingBottom: theme.spacing(8),
  },
}));

const Search = () => {
  const classes = useStyles();
  const [pageIndex, setPageIndex] = useState(1);

  const handlePageChange = (e, v) => {
    setPageIndex(v);
  }

  return (
    <div>
      <Container className={classes.cardGrid} maxWidth="md">
        <Grid container spacing={4}>
          <CardArea index={pageIndex} />
        </Grid>
      </Container>
      <Container className={classes.pageNation} maxWidth="lg">
        <Pagination
          page={pageIndex}
          count={maxCard}
          color="primary"
          size="large"
          onChange={handlePageChange}
          renderItem={(item) => (
            <PaginationItem
              page={item.page}
              component={Link}
              naked href={`/search${item.page === 1 ? '' : `?page=${item.page}`}`}
              {...item}
              />
          )}
        />
      </Container>
    </div>
  );
}

export default Search;

Data fetch部分(今回のメイン)

/components/Cards.js
import React from 'react';
import useSWR from 'swr';
import Card from '@material-ui/core/Card';
import CardContent from '@material-ui/core/CardContent';
import CardMedia from '@material-ui/core/CardMedia'
import Grid from '@material-ui/core/Grid';
import Typography from '@material-ui/core/Typography';
import { makeStyles } from '@material-ui/core/styles';
import Skeleton from '@material-ui/lab/Skeleton';

const useStyles = makeStyles((theme) => ({
  card: {
    height: '100%',
    display: 'flex',
    flexDirection: 'column',
  },
  cardMedia: {
    paddingTop: '56.25%',  //  16:9
  },
  cardContent: {
    flexGrow: 1,
  },
}));

const fetcher = (...args) => fetch(...args).then(res => res.json())

const Cards = ({ index }) => {
  const classes = useStyles();
  const { data, error } = useSWR(`api/test?${index}`, fetcher);
  const cards = data ? [].concat(data.test) : [];

  return (
    <>
    {cards.map((card, index) => {
      return (
        <Grid item xs={12} sm={6} md={4} key={index}>
          <Card className={classes.card}>
            <CardMedia
              className={classes.cardMedia}
              image={card.image}
              title="Design Image"
            />
            <CardContent className={classes.cardContent}>
              <Typography variant="h4" component="h2" align="center" gutterBottom>
                {card.title}
              </Typography>
              <Typography variant="h6" align="center" gutterBottom>
                <Skeleton animation="false" />
              </Typography>
            </CardContent>
          </Card>
        </Grid>
      );
    })}
    </>
  );
}

export default Cards;

おわりに

今回はswrを使ったPagiNationについて実験を行いました。
useSWRPagesの代用として登場したuseSWRInfiniteについても触ってみたので後々備忘録書きたいと思います。