1. 程式人生 > 其它 >React 路由 封裝

React 路由 封裝

React 路由 封裝

鴿了一段時間,終於迴歸React的陣營中,後面會完整製作一個專案,今天先講一下路由,後續會和專案一併講解。

主要目錄

我發現很多博主講封裝,一是轉載別人的,二又不說明 哪個打哪個檔案的程式碼,雲裡霧裡。

在這裡插入圖片描述
我們一般把 頁面元件(頁面)放到 component 裡面的 pages 裡,相當於 vue 的 view檔案,因為在React裡面,頁面也算是元件,所以,pages 理應放到 component 裡面。

我們每建立一個頁面都必須先建立資料夾,然後建立 index.js/index.jsx ,這樣既方便我們新增單獨頁面的樣式(如,在Index檔案裡建立多一個index.css),又方便我們新增頁面的 子頁面(如Test)。

router檔案中,
config.jsx 用於存放我們的路由列表,
index.jsx 是路由元件的入口
router-view.jsx 是我們每一個 Router 的封裝,後面會講到。

路由列表

config.jsx 
import { lazy } from 'react'

const routes = [
    {
        path: '/test',
        component: lazy(() => import('../pages/Test')),
        meta: {
            title: '測試頁面'
        },
        // 若有子頁面,此為參考
routes: [ { path: '/test/demo', component: lazy(() => import('../pages/Test/Demo')) }, { path: '/test/demo2', component: lazy(() => import('../pages/Test/Demo2')) } ] }, {
path: '/index', component: lazy(() => import('../pages/Index')), // 如果要求嚴格路徑 isExact: true, meta: { title: '首頁' } }, { path: '/login', component: lazy(() => import('../pages/Login')), meta: { title: '登入頁面' } }, { path: '/', component: lazy(() => import('../pages/Index')), meta: { title: '首頁' } }, { path: null, redirect: lazy(() => import('../pages/NotFound')), meta: { title: '404' } }, ] export default routes

這裡儘量做得與vue路由格式一樣

lazy嘛,顧名思義懶載入

寫這個路由列表,目的只是為了後期方便新增修改頁面


index.jsx

import React from 'react'

import routes from './config' // 路由列表,有其他的路由列表頁面可以繼續引入
import RouterView from './router-view'  // 封裝好的 Router
const routerList = [   // 將所有路由拼接在一起
    ...routes
]

const ViewRouter = () => {
    return (
        <div>
            <RouterView route={routerList} />  // 呼叫封裝好的 Router
        </div>
    )
}

export default ViewRouter

我們的目的是將繁瑣的路由封裝成類似於 vue 的 <view-router /> 一樣簡單實用


router-view.jsx

import {
    Switch,
    Redirect,
    Route
} from "react-router-dom"; // 引入 react-router-dom
import { Suspense } from 'react' // Suspense 配合前面的 laze() 使用,不加上會報錯

const RouterView = (props) => {
    let { route } = props // 拿到index.jsx頁面傳過來的 路由列表
    return (
        <Suspense fallback={<div>Loading...</div>}> // 載入時的dom
            <Switch>
                {
                    route.map((item, index) => {
                        return item.component ? <Route key={index} path={item.path} render={(props) => {
                            return <item.component route={item.routes} {...props} />
                        }}></Route> : <Redirect key={index} from={item.path} to={item.redirect} /> // 找不到對應的路由時 全部去到404頁面
                    })
                }
            </Switch>
        </Suspense>
    )
}

export default RouterView

這邊 首先通過 map() 遍歷 Route ,按照路由表格式傳遞引數。這裡用 render 而不是直接 component={} ,是因為我們可能有 巢狀子頁面的需求。一樣的,把routes (根據路由表的子頁面list)傳進去,這樣就完成了整個 Route 的封裝,無論我們有多少個巢狀子頁面,都可以直接使用。


正常來說,我們得先建立頁面,不然,路由頁面那邊會報錯,那麼我們就把頁面簡單過一下:

Index/index.jsx

import React, { Component } from 'react'

export default class index extends Component {

    goRouter = (path) => {
        return () => {
            this.props.history.push({
                pathname: path,
                state: null
            })
        }
    }

    render() {
        return (
            <div>
                <h3>index頁面</h3>
                <div onClick={this.goRouter('/login')}>Go Login</div>
            </div>
        )
    }
}

這裡說一下跳轉,react的跳轉不僅侷限於 Link/NavLink 的跳轉,我們在高階函式裡,通過 this.props.history.push()【帶痕跡】/ this.props.history.replace()【痕無跡】


Login/index.jsx

import React, { Component } from 'react'

export default class login extends Component {

    goRouter = (path) => {
        return () => {
            this.props.history.push({
                pathname: path,
                state: null
            })
        }
    }

    render() {
        return (
            <div>
                <h3>login頁面</h3>
                <div onClick={this.goRouter('/index')}>Go Index</div>
            </div>
        )
    }
}


NotFound/index.jsx

import React, { Component } from 'react'

export default class NotFound extends Component {
    render() {
        return (
            <div>
                404
            </div>
        )
    }
}

404頁面按自己的來


Test/index.jsx

import React, { Component } from 'react'
import { NavLink } from 'react-router-dom'
import RouterView from '../../router/router-view'

export default class test extends Component {
    render() {
        let {route} = this.props
        return (
            <div>
                <br />
                這是測試頁面
                <br />
                <br />
                <NavLink to="/test/demo">demo</NavLink>
                &nbsp;
                <NavLink to="/test/demo2">demo2</NavLink>
                <br />
                <br />
                <RouterView route={route} />
            </div>
        )
    }
}

test頁面是為了讓大家更好理解 巢狀子頁面做的一個例子

因為Text/idnex.jsx 頁面本身就是個頁面元件,我們在 router-view.jsx 頁面裡就已經往裡面傳了 route

return <item.component route={item.routes} {...props} />

所以我們是可以直接在 Text/index.jsx裡面 直接拿到route

let {route} = this.props

所以我們直接引用

import RouterView from '../../router/router-view'

並呼叫即可

<RouterView route={route} />

Text/Demo/index.jsx

import React, { Component } from 'react'

export default class demo extends Component {
    render() {
        return (
            <div>
                <h2>這是測試頁面的子頁面測試</h2>
            </div>
        )
    }
}

Text/Demo2/index.jsx

import React, { Component } from 'react'

export default class demo2 extends Component {
    render() {
        return (
            <div>
                <h2>這是測試頁面的子頁面測試2</h2>
            </div>
        )
    }
}


在App.jsx頁面引用路由元件

慣例先上程式碼

App.jsx

import { NavLink } from 'react-router-dom' 
import ViewRouter from './router/index' // 封裝好的路由
import './App.css';

function App() {
  return (
    <div className="App">

      <div className="nar">
        <NavLink to="/index">Index</NavLink>
        &nbsp;
        <NavLink to="/login">Login</NavLink>
        &nbsp;
        <NavLink to="/test">test</NavLink>
      </div>


      <div className="content">
        <ViewRouter />
      </div>
    </div>
  );
}

export default App;

就是一個引入並呼叫

注意

我們的路由是被 整個 BrowserRouter包裹起來才能生效,所以我們最後一步,直接在 index.js 頁面加上

import React from 'react';
import ReactDOM from 'react-dom';
import reportWebVitals from './reportWebVitals';
import { BrowserRouter as Router } from 'react-router-dom' // BrowserRouter
import App from './App';

ReactDOM.render(
  <Router>   // 直接把整個App包裹起來
    <App />
  </Router>,
  document.getElementById('root')
);

reportWebVitals();

搞定。。。。。。。
有問題請留言,因為程式碼量少,所以沒有原始碼下載