※当サイトの記事には、広告・プロモーションが含まれます。

ReactでSPA(Single Page Application)を実装してみる

www.itmedia.co.jp

 利用料金は、個人ユーザーは無料で利用可能。月間50回までのセキュリティスキャンも利用可能です。登録はメールアドレスのみで、AWSのアカウントも不要。

AWS版「GitHub Copilot」な「Amazon CodeWhisperer」が正式版に 個人ユーザーは無料、VSCodeに対応 - ITmedia NEWS

⇧ ありがたや、「GitHub  Copilot」は有償になったから手が出せんかったけども、こちらを試してみますかね。

ReactとVue、選択に迷うよね

JavaScriptフレームワークが様々あるけれど、3大フレームワークと言うと、

  • Angular
  • React
  • Vue

って感じになるとは思うのだけど、世界的にはReactが主流らしいですと。

最近、Vue 2.xから3.xでの破壊的変更があったせいで、移行作業に苦しめられた人にとっては、この先、同様の破壊的変更が起こるんじゃないかとVueに対する不信感が払拭できない今日この頃。

qiita.com

zenn.dev

⇧ 上記サイト様によりますと、Reactを選んでおく方が良さ気な雰囲気ですと。

Reactが推される風潮については、

ja.reactjs.org

⇧ hookという仕組みが導入されたことも大きいのかもしれません、知らんけど。

ReactでSPA(Single Page Application)を実装してみる

そも、SPA(Single Page Application)とは?

single-page application (SPA) is a web application or website that interacts with the user by dynamically rewriting the current web page with new data from the web server, instead of the default method of a web browser loading entire new pages. The goal is faster transitions that make the website feel more like a native app.

https://en.wikipedia.org/wiki/Single-page_application

In a SPA, a page refresh never occurs; instead, all necessary HTMLJavaScript, and CSS code is either retrieved by the browser with a single page load, or the appropriate resources are dynamically loaded and added to the page as necessary, usually in response to user actions.

https://en.wikipedia.org/wiki/Single-page_application

⇧ 目指してるのは、Native Applicationのような速いページ遷移ってことらしい。

SPA(Single Page Application)とMultiple Page Applicationの違いはと言うと、

www.excellentwebworld.com

⇧ 上図の左側のように、SPA(Single Page Application)は1つのページの中でコンテンツの内容だけ切り替えて読み込むため、ページ遷移が高速化されるということかと。

SEO(Search Engine Optimization)とか考慮する必要がないはずの業務システムなんかは、だいたいSPA(Single Page Application)で作る感じになるんじゃないかと。

で、ReactでSPA(Single Page Application)を実現するとなると、

qiita.com

⇧ 上記サイト様によりますと、

  • react-router
  • react-router-dom

の2つがメジャーらしいんだけども、

github.com

Declarative routing for React

https://github.com/remix-run/react-router

React Router is a lightweight, fully-featured routing library for the React JavaScript library. React Router runs everywhere that React runs; on the web, on the server (using node.js), and on React Native.

https://github.com/remix-run/react-router

This repository is a monorepo containing the following packages:

https://github.com/remix-run/react-router

スマホのようなNative Application向けのreact-router-nativeってのもあるらしい。

react-router-domでSPA(Single Page Application)

とりあえず、調べた感じでは、ReactでSPA(Single Page Application)を実現するにはreact-router-domを導入すれば良いらしい。

新規でReactのプロジェクトを作成できるのであれば、CLIで作る感じになるのかな?と思っていて

  • Create React App
  • Vite

の2つの方法が主流っぽいのだけど、「Vite」はVueの開発者のEvan You氏が開発してるものだそうです。

なんか、いまのところ、

zenn.dev

⇧「CRA(Create React App)」は改善に取り組もうと方針を検討中らしいので、「Vite」を使ってReactのプロジェクトを作成することにします。

「Vite」のGitHub のドキュメントによると、

github.com

⇧「Vite」で利用できるtemplateでReactに関係するものを選んでいく感じらしいです。

「Vite」を利用するには、事前に「Node.js」を導入しておく必要があるようです。

自分は、Windows環境なので「nvm-windows」をインストールして「Node.js」をインストールしています。

手前味噌で恐縮ですが、

ts0818.hatenablog.com

⇧ 前回の記事で、「nvm-windows」のバージョン上げてたりしてますので、宜しければご照覧ください。

「Node.js」のバージョンは、LTS(Long Term Support)版の18.16.0を利用してます。

で、「Vite」の公式のtemplateを見た感じ、ReactでSPAを実現するための「react-router-dom」は含まれていないので、「Vite」でReactプロジェクトを作成後に「react-router-dom」をnpm installしていく感じになるのかな。

ということで、まずは、Reactのプロジェクト用のディレクトリを作成したい場所に移動します。

そしたらば、作成したディレクトリに移動して、「Node.js」に同梱されてるnpmで公開されてる「Vite」のバージョン確認してみます。

4.2.0を利用していこうと思います。

ViteでReactプロジェクトの雛型を作成。

npm create vite@4.2.0 my-react-spa-app -- --template react-ts

⇧ 雛型が作成されたようです。

ここからは、Visual Studio Codeを使っていきます。

Visual Studio Codeを起動して、「File」>「Open Folder...」を選択して、先ほど作成されたReactのプロジェクトのフォルダを選択。

続いて、「View」>「Terminal」を選択。

「Command Prompt」を選択。

公開されているreact-router-domのバージョンを確認してみる。

2023年4月15日(土)時点の最新をインストールすることにします。

npm install react-router-dom@6.10.0

で、

zenn.dev

note.com

⇧ 上記サイト様によりますと、TypeScriptを使う場合は、「@types/react-router-dom」ってライブラリもインストールする必要があるらしい。

こちらも、今時点の最新をインストールしました。

npm install @types/react-router-dom@5.3.3    

package.jsonの依存関係に追加されてれるのでインストールされたようです。

{
  "name": "my-react-spa-app",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "tsc && vite build",
    "preview": "vite preview"
  },
  "dependencies": {
    "@types/react-router-dom": "^5.3.3",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-router-dom": "^6.10.0"
  },
  "devDependencies": {
    "@types/react": "^18.0.28",
    "@types/react-dom": "^18.0.11",
    "@vitejs/plugin-react": "^3.1.0",
    "typescript": "^4.9.3",
    "vite": "^4.2.0"
  }
}

そしたらば、まずは、遷移先のページを作成する必要があるようなので、適当にフォルダを作成してファイルを作成します。

ルーター用のファイルを作成。

今回、追加したフォルダとファイルは以下のようになりました。

追加したファイルにコーディング。

■C:\Users\Toshinobu\Desktop\soft_work\react_work\my-react-spa-app\src\page\home\index.tsx

export const Home = () => {
    return (
        <div>
            <h1>Home</h1>
        </div>
    );
}    

■C:\Users\Toshinobu\Desktop\soft_work\react_work\my-react-spa-app\src\page\about\index.tsx

export const About = () => {
    return (
        <div>
            <h1>About</h1>
        </div>
    );
}    

■C:\Users\Toshinobu\Desktop\soft_work\react_work\my-react-spa-app\src\page\404.tsx

export const Page404 = () => {
    return (
        <div>
            <h1>404</h1>
        </div>
    );
}    

■C:\Users\Toshinobu\Desktop\soft_work\react_work\my-react-spa-app\src\routes\router.tsx

import { Route, Routes } from "react-router-dom";
import { Home } from "../page/home";
import { About } from "../page/about";
import { Page404 } from "../page/404";

export const Router = () => {
    return (
        <Routes>
          <Route path="/" element={<Home/>} />
          <Route path="/about" element={<About/>} />
          <Route path="*" element={<Page404/>} />
        </Routes>
    );
}

あとは、既存のファイルに追加。

■C:\Users\Toshinobu\Desktop\soft_work\react_work\my-react-spa-app\src\App.tsx

import { useState } from 'react'
import reactLogo from './assets/react.svg'
import viteLogo from '/vite.svg'
import './App.css'
import { BrowserRouter } from 'react-router-dom';
import { Router } from './routes/router';

function App() {
  const [count, setCount] = useState(0)

  return (
    <div className="App">
      {/** 
      <div>
        <a href="https://vitejs.dev" target="_blank">
          <img src={viteLogo} className="logo" alt="Vite logo" />
        </a>
        <a href="https://reactjs.org" target="_blank">
          <img src={reactLogo} className="logo react" alt="React logo" />
        </a>
      </div>
      <h1>Vite + React</h1>
      <div className="card">
        <button onClick={() => setCount((count) => count + 1)}>
          count is {count}
        </button>
        <p>
          Edit <code>src/App.tsx</code> and save to test HMR
        </p>
      </div>
      <p className="read-the-docs">
        Click on the Vite and React logos to learn more
      </p>
      */}
      {/* ルーター追加 */}
      <BrowserRouter>
        <Router/>
      </BrowserRouter>
    </div>

  )
}

export default App

で、開発用のサーバー起動。

ブラウザで、上記のリンクにアクセスする。

アクセス先を変更。

上記以外の場合は、404に遷移できてます。

とりあえずは、ReactでSPA(Single Page Application)を実現できたということで。

formとかも追加してサーバー側にリクエストすることもしていきたいですかね。その前に、hookの使い方やら、状態管理やらに慣れていくのが先ですかね...

2023年4月16日(日)11:40 追記:↓ ここから

型を付ける書き方を、

www.webopixel.net

⇧ 上記サイト様を参考にやってみました。

■C:\Users\Toshinobu\Desktop\soft_work\react_work\my-react-spa-app\src\page\home\index.tsx

import React from 'react'

const Home: React.FC = () => {
    return (
        <div>
            <h1>Home</h1>
        </div>
    );
}

export default Home

■C:\Users\Toshinobu\Desktop\soft_work\react_work\my-react-spa-app\src\page\about\index.tsx

import React from 'react';

const About:React.FC = () => {
    return (
        <div>
            <h1>About</h1>
        </div>
    );
}

export default About

■C:\Users\Toshinobu\Desktop\soft_work\react_work\my-react-spa-app\src\page\404.tsx

import React from 'react'

const Page404: React.FC = () => {
    return (
        <div>
            <h1>404</h1>
        </div>
    );
}

export default Page404

■C:\Users\Toshinobu\Desktop\soft_work\react_work\my-react-spa-app\src\routes\router.tsx

import { RouteObject } from "react-router-dom";
import Home from "../page/home";
import About from "../page/about";
import Page404 from "../page/404";

export const Router: RouteObject[] = [
    {
      path: '/',
      element: <Home />
    },
    {
      path: '/about',
      element: <About />
    },
    {
      path: '*',
      element: <Page404 />
    }
]

 

■C:\Users\Toshinobu\Desktop\soft_work\react_work\my-react-spa-app\src\App.tsx

import { useState } from 'react'
import reactLogo from './assets/react.svg'
import viteLogo from '/vite.svg'
import './App.css'
import { useRoutes, BrowserRouter } from 'react-router-dom';
import { Router } from './routes/router';
import React from 'react'

const App: React.FC = () => {
  const [count, setCount]: [number, React.Dispatch<React.SetStateAction<number>>] = React.useState<number>(0)

  const router: React.ReactNode = useRoutes(Router)
  return (
    <div className="App">
      {/** 
      <div>
        <a href="https://vitejs.dev" target="_blank">
          <img src={viteLogo} className="logo" alt="Vite logo" />
        </a>
        <a href="https://reactjs.org" target="_blank">
          <img src={reactLogo} className="logo react" alt="React logo" />
        </a>
      </div>
      <h1>Vite + React</h1>
      <div className="card">
        <button onClick={() => setCount((count) => count + 1)}>
          count is {count}
        </button>
        <p>
          Edit <code>src/App.tsx</code> and save to test HMR
        </p>
      </div>
      <p className="read-the-docs">
        Click on the Vite and React logos to learn more
      </p>
      */}
      {/* ルーター追加 */}
      {/* 
      <BrowserRouter>
        <Router/>
      </BrowserRouter>
      */}
      <>{router}</>
    </div>

  )
}

export default App

■C:\Users\Toshinobu\Desktop\soft_work\react_work\my-react-spa-app\src\main.tsx

import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
import './index.css'
import {BrowserRouter} from 'react-router-dom'

ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
  <React.StrictMode>
    <BrowserRouter>
      <App /> 
    </BrowserRouter>
  </React.StrictMode>,
)

どうしても、App.tsxの10行目とか変数の型が複雑になりますな...any型を指定してしまいたくなるよね...

まぁ、そもそも、count、setCountの値を使ってる個所をコメントアウトしてるから、使ってないんだけどね...

ただ、型付けが分かり辛いのは、TypeScriptがイケてないのか、Reactがイケてないのか...

あと、

qiita.com

⇧ 上記サイト様によりますと、「react-router-dom」はバージョン5系とバージョン6系でコーディングの仕方が結構変わってくるようです。

2023年4月16日(日)11:40 追記:↑ ここまで

毎度モヤモヤ感が半端ない...

今回はこのへんで。