iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 28
0
Modern Web

給初入JS框架新手的React.js入門系列 第 28

【React.js入門 - 28】 我要更多更多的分頁 - react-router-dom (下)

Link v.s <a>

如果我們想讓使用者用GUI導向不同頁面,過去會使用<a>。而react-router-dom提供了一個和<a>功能相同的元件 - Link。他的基礎語法是:

<Link to="路徑"> 顯示文字 </Link>

實際渲染時它會轉成<a>,並幫你根據前端路由導向正確href。

咦? 為什麼不用<a>就好,還要多生一個Link出來?

主要的原因是<a>的根路徑沒有辦法根據前端router去更動,而Link可以。以在我們的上一篇的練習為例,但如果要使用<a>的話,我們要自己幫<a>中的路徑加上「#」,才能導向正確路徑。

那我就加個「#」就好啦?

以前我也是這樣想,直到某天我必須「在伺服器的子使用者建立專案」。我的專案部署路徑是在主使用者domain/~子使用者名稱底下,預設也是讓使用者用這個路徑來存取我的網頁。可是<a>無法偵測子使用者。所以當我在自己電腦開發時使用<a href="/#/home"></a>,實際部署時卻會導向主使用者domain/#/home,而不是主使用者domain/~子使用者名稱#/home。導致最後我要把自己電腦開發和部署分成不同的版本,hen麻煩。

另外Link可以透過to以類似GET或POST的方法傳參數到前一篇講過的location物件中,有興趣的可以了解一下。

現在,我們來在firstPage.js和SecondPage.js中都加入可以切換頁面的UI。

先引入Link:

import {Link} from 'react-router-dom';

再加入可以導向兩個頁面的Link作為nav:

    return(
        <div style={StyleSheet}>
            <nav>
                <Link to="/">點我連到第一頁</Link>
                <Link to="/second" style={{marginLeft:"20px"}}>點我連到第二頁</Link>
            </nav> 
            <h1 style={{color:"white",fontFamily:"Microsoft JhengHei"}}>我是第一頁</h1>
        </div>
    )

記得先回去把route的path中要求的參數移除或是設為非必須。

執行結果:

在react-router-dom實現固定Layout的方法

在前面的練習中,我們的Link在firstPage.js和SecondPage.js中都是固定的Layout,卻因為在不同的Component而導致要重新render。這並不是我們喜歡的狀況。所以,現在我們就讓背景和Link獨立出來成固定Layout,讓頁面改變的只有文字。

step 1: 首先,請新增一個Layout.js,並宣告、輸出同名的函式。

import React from 'react';

const Layout=(props)=>{
    return(

    );
}
export default Layout;

step 2: 接著,把剛剛背景跟Link的部分移過來

import {Link} from 'react-router-dom';
const Layout=(props)=>{
    const StyleSheet={
        width:"100vw",
        height:"100vh",
        backgroundColor:"#FF2E63",
        display: "flex",
        alignItems:"center",
        justifyContent:"center",
        flexDirection:"column"
    }
    return(
        <div style={StyleSheet}>
            <nav>
                <Link to="/">點我連到第一頁</Link>
                <Link to="/second" style={{marginLeft:"20px"}}>點我連到第二頁</Link>
            </nav> 

        </div>
    );
}

step 3: 刪掉FirstPage.js和SecondPage.js中背景和Link的地方

    return(
            <h1 style={{color:"white",fontFamily:"Microsoft JhengHei"}}>我是第一頁</h1>
    )

step 4: 在App.js中,在Switch和Route之間,用Layout把Route夾起來

要放在Switch底下的原因是,Switch會把前面所提像是location這些傳給route元件的props傳給Layout,我們就能在Layout元件中根據不同路由參數呈現不同功能/樣貌。

import React from 'react';
import {HashRouter,Route,Switch} from "react-router-dom";
import FirstPage from "./FirstPage";
import SecondPage from "./SecondPage";
import Layout from "./Layout"; //記得要引入

const App=()=>{
    return( 
        <HashRouter>
            <Switch>
                <Layout>
                    <Route exact path="/" component={FirstPage}/>
                    <Route path="/second" component={SecondPage}/>
                </Layout>
            </Switch>
        </HashRouter>
    );
}
export default App;

step 5: 回到Layout.js,在原本文字的地方加入props.children

因為route回傳的元素夾在Layout標籤內,所以要用children來取得

    return(
        <div style={StyleSheet}>
            <nav>
                <Link to="/">點我連到第一頁</Link>
                <Link to="/second" style={{marginLeft:"20px"}}>點我連到第二頁</Link>
            </nav> 
            {props.children}
        </div>
    );

以上是固定的背景和Link的做法,不過我們原本會一起改變的背景顏色也在Layout.js中跟著被固定了,所以來讓它根據路徑來更改吧!

Bonus: 讓Layout.js根據路徑改變背景顏色

這邊要用到上一篇提過的location當中的pathname,比較如果為/就讓backgroundColor變成紅色,否則變成青色。

    const StyleSheet={
        width:"100vw",
        height:"100vh",
        backgroundColor:(props.location.pathname==="/")?"#FF2E63":"#08D9D6",
        display: "flex",
        alignItems:"center",
        justifyContent:"center",
        flexDirection:"column"
    }

這樣就完成了只更改不同route的Layout架構。

你可能會查到的舊資料

在過去react-router-dom實踐固定layout的方法是這樣的

    <Route path="/" component={Layout}/>
        <Route exact path="" component={FirstPage}/>
        <Route path="second" component={SecondPage}/>
    </Route>

但是大約在react-router-dom Ver.4 的時候,新增了route不能成為route的children的規定,所以必須使用前述的方式來實現固定layout。

綁定在Route中元件的props

如果是用Route的component去綁定元件的話,是沒有辦法綁props的。必須使用Route另一個props - render,以函式return值的方式綁定在它上面。以下是用這種方式「在SecondPage的props綁定一個為5的id」的語法:

<Route path="/second" render={()=>{return( <SecondPage id={5}/> )}}/>

原本綁component的方式是透過React.creactElement的方式創造元件。而這種綁render的方式等同於你在Route的props中製造並呼叫一個「渲染的元件的function」。在這一篇文章中有做詳細的解釋。

透過在Route中綁定元件的props,我們就能在Route與Route之間(子對子)、Route與Layout之間(子對子)、Route與做為Router控制中心的元件之間(子對父or父對子)做溝通。溝通的方法和我在【React.js入門 - 21】 Component的溝通所講的相同,就不再詳述了。

小結

這篇是此系列最後一個獨立出來講的React.js工具,下一篇把之前都沒有特別講但很常用到的東西提一下(像是css檔之類的),然後我會開始慢慢把這個系列作收尾,來統整一下個人認為新手可能遇到的狀況。


上一篇
【React.js入門 - 27】 我要更多更多的分頁 - react-router-dom (上)
下一篇
【React.js入門 - 29】 使用圖片、使用css檔、新手容易遇到的問題
系列文
給初入JS框架新手的React.js入門31

尚未有邦友留言

立即登入留言