iT邦幫忙

2023 iThome 鐵人賽

DAY 25
0
Modern Web

連我阿公都會-手把手教你架網站 系列 第 25

【Day25】淺談 React.js(4)公共元件 & 頁面跳轉 Router

  • 分享至 

  • xImage
  •  

在碰到純前端的大專案時,專案內有許多頁面是必然的。都是在同個專案,當頁面跳轉時,想必也都會使用到相同的元件。但是,在創建新頁面時,我們不僅要複製多個元件,甚至是整個檔案 ── 如果要對單一元件(如:menu)進行修改,便需要對每一個檔案的該元件進行修改,不覺得這大幅降低了我們在撰寫專案的效率嗎?

而我們今天便是要向您展示,如何使用React的公共元件和頁面跳轉以避免上述的情況!

首先要提到的是,公共元件的切板,我們使用的設計是前幾天教過的header,詳情請參考 ⇒ 【Day19】常見切版應用(3-1)頁頂Header實作

頁頂Header


在public資料夾內創建基本的檔案:
https://ithelp.ithome.com.tw/upload/images/20231010/20160488bNkEtb2GWG.png

// Header.js
const Header = () => {
    return (
        <></>
    )
}

export default Header;

將header.js創建完畢後,把第19天寫好的Header樣式貼上:
https://ithelp.ithome.com.tw/upload/images/20231010/201604889hdZJryCJk.png

並把class全部改成className,而後將fontAwesome元件引入:

import "./Header.css";

import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faBars } from "@fortawesome/free-solid-svg-icons";

const Header = () => {
    return (
        <header>
            <div className="container header">
                <div className="header-logo" style={{color:"white"}}>
                    @ this is a logo
                </div>
                <div className="menu-link">
                    <a href="#page1">go page1</a>
                    <a href="#page2">go page2</a>
                    <a href="#page3">go page3</a>
                    <a href="#page4">go page4</a>
                    <a href="#page5">go page5</a>
                </div>

                <button className="menu-btn">
                    <FontAwesomeIcon icon={faBars} style={{color: "#ffffff",}} />
                </button>
            </div>
        </header>
    )
}

export default Header;

此處我們先把homePage的元件刪除,這樣比較好操作:
https://ithelp.ithome.com.tw/upload/images/20231010/20160488wAWHADdBHW.png

再來是RWD的部分,這部份我們需要對header加入幾種狀態:

https://ithelp.ithome.com.tw/upload/images/20231010/20160488dxLAtMacVj.png
上圖截自 ⇒ 【Day19】常見切版應用(3-1)頁頂Header實作

import "./Header.css";

import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faBars } from "@fortawesome/free-solid-svg-icons";

import { useEffect,useState,useRef } from "react";
import useRWD from "../useRWD.js";

const Header = () => {
    const hamburger = useRef();
    const menu = useRef();
    const [menuStatus, setMenuStatus] = useState(false);
    const menuClick = () => {
        setMenuStatus(
            function (prev) {
                return !prev;
            }
        );
    }
    useEffect(() => {
        if (menuStatus) {
            menu.current.style.display = "flex";
        } else {
            menu.current.style.display = "none";
        }
    }, [menuStatus]);

    return (
        <header>
            <div className="container header">
                <div className="header-logo" style={{color:"white"}}>
                    @ this is a logo
                </div>
                <div className="menu-link" ref={menu}>
                    <a href="#page1">go page1</a>
                    <a href="#page2">go page2</a>
                    <a href="#page3">go page3</a>
                    <a href="#page4">go page4</a>
                    <a href="#page5">go page5</a>
                </div>

                <button className="menu-btn" ref={hamburger} onClick={menuClick} style={{color:"white"}}>
                    <FontAwesomeIcon icon={faBars} style={{color: "white"}} />
                </button>
            </div>
        </header>
    )
}

export default Header;

將按鈕事件處理妥當。

https://ithelp.ithome.com.tw/upload/images/20231010/20160488jPwTTmrb1Z.png
上面程式碼中,我們使用到了新的語法:useRef()

useRef() 的用法相當於jQuery的選擇器的概念,可以方便我們對DOM元件進行操作。

使用useRef()的時候我們要先在前面宣告一個變數,才能往下面的元件加入ref的傳入值。

而要使用useRef()得到此物件的DOM,則要使用 .current語法才能拿到。

如下圖所示:
https://ithelp.ithome.com.tw/upload/images/20231010/20160488qUwjRfraxa.png

撰寫完畢後,當我們點擊按鈕時,便會有效果了:
https://ithelp.ithome.com.tw/upload/images/20231010/201604886UsZijwgWv.png

但是會發現,當我們對頁面進行縮放時,還是會產生頁面的link區域不見的問題。

想要解決這個問題,我們必須去追蹤頁面的寬度,檢視當寬度變成多少時,需要作出變更。
https://ithelp.ithome.com.tw/upload/images/20231010/20160488yumOPc5Wlx.png

所以我們要在public創建一個 useRWD.js 的檔案。

比較不同的是,這裡我們並不需要回傳元件,而是要回傳資料:

// global/useRWD.js
const useRWD = () => {

}

export default useRWD;

新增一個mobile的狀態,用來記錄是否為手機頁面:

import { useState,useEffect } from "react";

const useRWD = (pixel) => {
    const [mobile,setMobile] = useState(false);
    const handleRWD = () => {
        if (window.innerWidth >=pixel){
            setMobile(true)
        } else {
            setMobile(false)
        }
    }
}

export default useRWD;

使用 useEffect() 去追蹤mobile的狀態:

import { useState,useEffect } from "react";

const useRWD = (pixel) => {
    const [mobile,setMobile] = useState(false);
    const handleRWD = () => {
        if (window.innerWidth >=pixel){
            setMobile(true)
        } else {
            setMobile(false)
        }
    }
    useEffect(()=>{
    
        window.addEventListener('resize',handleRWD);
        handleRWD();
        
        return(()=>{
            window.removeEventListener('resize',handleRWD);
        })
    },[]);
		
		return mobile;
}

export default useRWD;

回到我們的 Header.js ,並把 useRWD() 加進去:

const device = useRWD(770);
useEffect(() => {
    if (device) {
        hamburger.current.style.display = "none";
        menu.current.style.display = "flex";
    } else {
        hamburger.current.style.display = "block";
        menu.current.style.display = "none";
    }
}, [device])

完整代碼如下:
https://ithelp.ithome.com.tw/upload/images/20231010/20160488Qfk3AjVBx5.png
https://ithelp.ithome.com.tw/upload/images/20231010/20160488Dz6AH7sDtU.png

header完成了!

再來我們要做router的部分了:

欲使用router的部分,我們需要引入react的Link component,它的作用與 <a> 相似。
https://ithelp.ithome.com.tw/upload/images/20231010/20160488cp1ZmDe9ps.png
https://ithelp.ithome.com.tw/upload/images/20231010/20160488fgdyCfQIMq.png
(這裡我為了Demo又再多加了幾個頁面)

接下來,我們要去下載一個包:React Router DOM ⇒ https://www.npmjs.com/package/react-router-dom
https://ithelp.ithome.com.tw/upload/images/20231010/2016048840SE0Jzjyt.png

安裝完畢:
https://ithelp.ithome.com.tw/upload/images/20231010/201604886IGZa3RLKn.png

回到 index.js ,這裡我們需要引入React Router DOM的幾個元件:BrowserRouter, Routes, Route

並像下方展示的樣子把元件填進去:
https://ithelp.ithome.com.tw/upload/images/20231010/20160488u7SCZ4i6G5.png
https://ithelp.ithome.com.tw/upload/images/20231010/20160488cV8vuO75li.png

而這裡對應的每個值便是您方才在header內寫的link值。

如此一來,我們的header便完成了!
https://ithelp.ithome.com.tw/upload/images/20231010/20160488vYYdE27xr3.png

切換到另一個頁面後,內容物也是一樣的:
https://ithelp.ithome.com.tw/upload/images/20231010/20160488L7iBzQ3Wwr.pnghttps://ithelp.ithome.com.tw/upload/images/20231010/20160488cLX7n9kewC.pnghttps://ithelp.ithome.com.tw/upload/images/20231010/20160488nEm0VeKIoh.png

由此往後延伸,您可以在元件的前面或後面添加些新的東西,就可以讓此元件一次出現在不同的頁面中:
https://ithelp.ithome.com.tw/upload/images/20231010/2016048888QOiiKiPz.png


那今天的教學就到這裡了,寫完之後是不是 ── 讓您不想繼續碰前端了呢?(誤

沒問題haha,因為明天我們將要進入到Python的部分!

「甚麼?Python也能寫網頁嗎?」沒錯!敬請期待接下來的篇章吧!


上一篇
【Day24】淺談 React.js(3)React useState & useEffect
下一篇
【Day26】Python速成班
系列文
連我阿公都會-手把手教你架網站 30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
凱文大叔
iT邦新手 5 級 ‧ 2023-11-29 11:23:39

遇到一個問題很困擾,我使用 或是 useNavigate 跳轉頁面時 header 的 Token 不知如何設定,都會被塞入一個過期的 Token,導致驗證失敗無法產生內容,這部分該如何處理比較好?

我要留言

立即登入留言