react教學系列

在做前端的時候,都會碰到多個頁面切換的畫面,而透過React Router這個套件,就能簡單的管理跳轉頁面的問題

SPA跟SSR的比較表

SPA切換頁面需要像伺服器請求,並且會轉換網址,尤其剛開始拿到的是空白頁面,對使用者體驗差,google爬蟲抓取資料不易,對SEO排名有影響,但相對就不用兼顧伺服器部分,開發成本低

 SPA單頁應用SSR伺服器渲染
伺服器負擔
使用者體驗
SEO排名較差較好
HTML一開始空白對應頁面的內容
開發成本較低較高

Router安裝

先來到官網,並且點選Read the Docs,並到左邊有個GTTING STARTER裡面的Installation。選好之後頁面的Basic Installation有npm安裝的指令

npm install react-router-dom@6

引入套件

剛剛的安裝頁面繼續往下找,有一個Create React App,在這裡面有import的程式碼,以及將你要有路由的組件用< BrowserRouter>包覆起來

import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import { BrowserRouter } from "react-router-dom";

ReactDOM.render(
  <React.StrictMode>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </React.StrictMode>,
  document.getElementById("root")
);

繼續往下移,可以看到app.jsx要改的內容

先將react-router-dom給import進來,分別為Routes, Route, Link

  • Routes是有很多Route的時候,要用來包覆這些路由的外層,是依附在BrowserRouter底下的
  • Route的用法就是你要的路徑(path),對應要轉換的組件element
import * as React from "react";
import { Routes, Route, Link } from "react-router-dom";
import "./App.css";

function App() {
  return (
    <div className="App">
      <h1>Welcome to React Router!</h1>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="about" element={<About />} />
      </Routes>
    </div>
  );
}

接下來就是把home跟about組件加入進去,也在網頁裡往下移都有範例

這裡面用到link跟<a href>差不多,只是不用在刷新頁面的情況下,去切換頁面

// App.js
function Home() {
  return (
    <>
      <main>
        <h2>Welcome to the homepage!</h2>
        <p>You can do this, I believe in you.</p>
      </main>
      <nav>
        <Link to="/about">About</Link>
      </nav>
    </>
  );
}

function About() {
  return (
    <>
      <main>
        <h2>Who are we?</h2>
        <p>That feels like an existential question, don't you think?</p>
      </main>
      <nav>
        <Link to="/">Home</Link>
      </nav>
    </>
  );
}

顯示多個路徑

選到官網的GTTING STARTER裡面的Tutorial。Nested Routes裡面就是在教怎麼放多個路徑,把Route 改成<Route> </ Route>,包裹住要加入的頁面組件

另外從原本的組件修改,在about加main

  • 建立一個main組件
  • 放入about的Route裡面
  • 將outlet給import進來
  • 在about裡面使用
import { Routes, Route, Link, Outlet } from "react-router-dom";

function App() {
  return (
    <div className="App">
      <h1>Welcome to React Router!</h1>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="about" element={<About />}>
          <Route path="main" element={<Main />} />
        </Route>
      </Routes>
    </div>
  );
}
function Main() {
  return (
    <>
      <p>main標籤</p>
    </>
  );
}

function About() {
  return (
    <>
      <main>
        <h2>Who are we?</h2>
        <p>That feels like an existential question, don't you think?</p>
      </main>
      <nav>
        <Link to="/">Home</Link>
      </nav>
      <Outlet />
    </>
  );
}

改成動態的路由

這邊改成放入:Item,也就是在about後面不管接什麼,都會引導到Item這個頁面,通常是用在放用戶ID或是有好幾個頁面

function App() {
  return (
    <div className="App">
      <h1>Welcome to React Router!</h1>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="about" element={<About />}>
          <Route path=":Item" element={<Item />} />
        </Route>
      </Routes>
    </div>
  );
}
function Item() {
  return (
    <>
      <p>main標籤</p>
    </>
  );
}

抓取Url

在官網的Reading URL Params中有提到一個hook { useParams },可以用他來抓取

在剛剛的範例中把useParams給import進來

使用這個useParams()把Url抓下來

import { Routes, Route, Link, Outlet, useParams } from "react-router-dom";
function Item() {
  const url = useParams();
  console.log("url", url);
  return (
    <>
      <p>main標籤</p>
    </>
  );
}

HTML元件加上跳轉

看到官網的Navigating Programmatically

在拿剛剛的範例來改,把link改成button之後,透過useNavigate,改成可以跳轉頁面的功能

  • 先將useNavigate給import進來
  • 再將useNavigate()實作出來
  • 並使用點擊事件引入切換頁面功能
import {  Routes,  Route,  Link,  Outlet,  useParams,  useNavigate,
} from "react-router-dom";
function Home() {
  let navigate = useNavigate();
  return (
    <>
      <main>
        <h2>Welcome to the homepage!</h2>
        <p>You can do this, I believe in you.</p>
      </main>
      <nav>
        {/* <Link to="/about">About</Link> */}
        <button
          onClick={() => {
            navigate("/about");
          }}
        >
          about
        </button>
      </nav>
    </>
  );
}

使用config的寫法

在官網的Route Objects可以找到範例,那就是把他整理成json的格式,這樣將來要引入到別的地方也比較方便操作

那繼續拿剛剛的範例

  • 把useRoutes跟RouteObject給import進來
  • 把RouteObject當作一個陣列型態
  • 組成方式最外面為陣列,每一個Route為一個物件{ },要有path跟element
  • path放入路徑、element放組件
  • 而有子路徑的放children,children的組成也是一個陣列在外,裡面繼續包Route為一個物件{}
  • 最後將 RouteObject宣告的內容用useRoutes實作出來
  • 最後放入return渲染出來就OK囉
import {  Routes,  Route,  Link,  Outlet,  useParams,  useNavigate,  RouteObject,  useRoutes,} from "react-router-dom";
let routerConfig: RouteObject[] = [
  {
    path: "/",
    element: <Home />,
  },
  {
    path: "/about",
    element: <About />,
    children: [
      {
        path: "/about:Item",
        element: <Item />,
      },
    ],
  },
];
function App() {
 
  const elements = useRoutes(routerConfig);
  return (
    <div className="App">
      <h1>Welcome to React Router!</h1>
      {/* <Routes>
        <Route path="/" element={<Home />} />
        <Route path="about" element={<About />}>
          <Route path=":Item" element={<Item />} />
        </Route>
      </Routes> */}
      {elements}
    </div>
  );
}

切換沒有設定的頁面

那當網址打錯得時候,可以預設一個沒有的頁面給他

  • 設定一個NoMatch的組件
  • 然後加入到剛剛設定的routerConfig
  • 在下面再新增一個route的物件,path為*,組件就是NoMatch
const NoMatch: React.FC = () => {
  return (
    <>
      <p>沒有此頁面</p>
    </>
  );
};
let routerConfig: RouteObject[] = [
  {
    path: "/",
    element: <Home />,
  },
  {
    path: "/about",
    element: <About />,
    children: [
      {
        path: "/about:Item",
        element: <Item />,
      },
    ],
  },
  {
    path: "*",
    element: <NoMatch />,
  },
];

Webpack Server取得跳轉功能

2023/3/17更新

研究原因

以上範例都是用npx create-react-app my-app的專案所做的練習,後續為了更深入研究React,我研究了Webpack從0建置及加入TypeScript跟React跟React Router

解決的問題

從頭開始建置的專案,在啟動Webpack Server,會遇到輸入網址無法跳轉的問題,這時候要在webpack.config.js做一點修改

  • devServer新增historyApiFallback: true,
    • 利用HTML5 History API來實現路由跳轉,訪問一個不存在路由時,會跳轉到指令頁面
  • 在outpur新增publicPath: ‘/’
    • output.publicPath是”/”時,表示根路徑是”/”,這樣使用react-router-dom可以正確地加載
module.exports = { 
  output: {
    publicPath: '/',
  },

  devServer: {
    historyApiFallback: true,  
  },
};

結論

今天持續學習布魯斯的 TypeScript + React 全攻略|快速上手仿 Instagram UI,在課程中布魯斯詳細的講解SPA跟SSR的運作邏輯,而伺服器渲染的方式對於一個開始懂得管理資源,控制開發流程及注重效能來說,是非常重要的觀念,所以很開心在學習React Router之餘,還有學習到這些觀念

而後面也針對Router真的在上傳到server時,所遇到的問題及解決的觀念,讓我覺得非常值得,畢竟花時間都不一定查的到這些bug的原因,讓我以後可以直接避掉雷坑

那至於React Router本身的學習應用並不是相當困難,但確實很重要的觀念,我們在拿到陌生專案的時候,第一個可以先打開的檔案,就是router的config,去看看整個程式的頁面架構長什麼樣子,減少我們探索的時間

布魯斯的 TypeScript + React 全攻略|快速上手仿 Instagram UI

By dong

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *