Reactアプリでのページ遷移の実装が不適切だったので修正してみた

2021.10.05

こんにちは、CX事業本部 IoT事業部の若槻です。

今回は、以前のエントリで紹介したReactアプリケーションのサンプルでのページ遷移の実装が不適切だったので修正してみました。

以前(修正前)の実装

以前の修正前のエントリというのが以下の記事です。

上記エントリ中で紹介しているアプリケーションを下記のCodeSandboxの環境にデプロイしています。(実際に開いて利用できます。)

このアプリケーションではStartページでボタンクリックによるページ遷移が行われ、さらにThankYouページで時間経過によるページ遷移が行われます。

さて、下記はそのアプリケーションのページ遷移の様子ですが、Developer Toolのネットワークコンソールを見て分かる通り、ページ遷移のたびにページ読み込みが走っています。

Reactは、SPA(Single Page Application)であり、初回のページ読み込み時にアプリケーションのすべてのページリソースがブラウザにダウンロードされます。よってアプリケーション内のページ遷移(別のパスへの移動)であれば再読み込みをすることなく遷移が可能です。しかし以前の実装では実装が不適切であったためページ遷移のたびにページ読み込みが行われ不要なレイテンシーが発生していました。

修正後の実装

そこで、ページ遷移のたびにページ読み込みを行わないように実装を適切に修正したものが下記です。CodeSandboxの環境にデプロイしています。

修正が必要なポイントとしてはJavaScriptのwindow.location.href = "/path"を使用するのでなく、ReactのRouting機能をきちんと使う、これに尽きました。Routing機能を使えばアプリケーション内では再読み込みをせずにページ遷移ができるのですが、window.location.href = "/path"を使用すると新しくURLからページを問答無用で読み込んでしまうためです。

ボタンクリックによる遷移の修正

StartページからThankYouページへのボタンクリックによるページ遷移では、react-router-domLink<Button>コンポーネントで使用することによりRoutingを行うように修正しました。

/src/pages/StartPage.tsx

import React from 'react';
import { Link } from 'react-router-dom';
import { makeStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';
import Typography from '@material-ui/core/Typography';

const useStyles = makeStyles((theme) => ({
  typography: {
    marginTop: theme.spacing(20),
    marginBottom: theme.spacing(10)
  },
  button: {
    marginTop: 'auto',
    marginBottom: theme.spacing(5),
    width: '250px',
    height: '200px',
    fontSize: '30px'
  }
}));

const StartPage: React.FC = () => {
  const classes = useStyles();

  return (
    <div>
      <Typography
        variant="h2"
        align="center"
        className={classes.typography}
      >
        <div>{'アンケートを開始します。'}</div>
      </Typography>
      <div
        style={{
          display: 'flex',
          justifyContent: 'center'
        }}
      >
        <Button
          variant="contained"
          color="primary"
          className={classes.button}
          component={Link}
          to="/thankyou"
        >
          {'開始'}
        </Button>
      </div>
    </div>
  );
};

export default StartPage;

時間経過による遷移の修正

ThankYouページからStartページへの時間経過によるページ遷移では、react-router-domuseHistoryを使用することによりRoutingを行うように修正しました。

/src/pages/ThankYouPage.tsx

import React, { useEffect } from 'react';
import { useHistory } from 'react-router-dom';
import { makeStyles } from '@material-ui/core/styles';
import Typography from '@material-ui/core/Typography';

const useStyles = makeStyles((theme) => ({
  typography: {
    marginTop: theme.spacing(30),
    marginBottom: theme.spacing(30)
  }
}));

const ThankYouPage: React.FC = () => {
  const classes = useStyles();

  let history = useHistory();
  useEffect(() => {
    setTimeout(() => {
      history.push('/start');
    }, 3 * 1000);
  }, [history]);

  return (
    <Typography
      variant="h2"
      align="center"
      className={classes.typography}
    >
      <div>{'お疲れさまでした。'}</div>
      <div>{'3秒後にスタートページに戻ります。'}</div>
    </Typography>
  );
};

export default ThankYouPage;

下記は、修正後の実装のアプリケーションのページ遷移の様子です。Developer Toolのネットワークコンソールを見て分かる通り、ページ遷移をしてもページ再読み込みは行われていません。そして修正前と比べて明らかに遷移後のページ表示が早くなっています。

おわりに

以前のエントリで紹介したReactアプリケーションのサンプルでのページ遷移の実装が不適切だったので修正してみました。

後で気付いて修正前の実装はSPAを使うメリットをまるで活かせておらずひどいなと思いました。二ヶ月半も掛かってしまいましたが気付けて良かったです。

参考

以上