用React刻自己的投资Dashboard Day17 - Dashboard 2.0版路由功能

tags: 2021铁人赛 React

如Day15的wireframe,为了要加上更多的功能,因此要在顶端列新增几个按钮,每个按钮代表不同的路由,而不同的路由会导引到不同的页面。本篇就先做到点击顶端列按钮可以跳转页面吧!

安装react-router-dom

首先打开terminal并切换至专案资料夹,并执行下面这行,就会安装好套件了。

npm install react-router-dom

Navbar制作新按钮

这边还是使用react-bootstrap的Nav元件来制作连结按钮,也就是下面程序码的Nav.Link,目前先规划首页与总体经济两个页面,先作到两个路由可以切换为主。

src\components\Navbar\Navbar.js

import React from 'react';
import styles from './Navbar.module.css';
import Navbar from 'react-bootstrap/Navbar';
import svgIcon from './navbaricon.svg';
import Nav from 'react-bootstrap/Nav';

const Topbar = () => {
  return (
    <Navbar className={styles.navbar}>
      <Navbar.Brand className={styles.title} href="/">
        <img
          alt=""
          src={svgIcon}
          width="30"
          height="30"
          className="d-inline-block align-top"
        />{' '}Invsetment Dashboard
      </Navbar.Brand>
      <Navbar.Collapse id="responsive-navbar-nav">
        <Nav className="me-auto">
          <Nav.Link href="/">首页</Nav.Link>
          <Nav.Link href="/macroeconomics">总体经济</Nav.Link>
        </Nav>
      </Navbar.Collapse>
    </Navbar>
  );
};

export default Topbar;

做好後的画面长这样,上面有两个按钮,分别是首页及总体经济。

制作页面元件

目前有两个页面分别是Home与Macroeconomics,先将这两个分页加到components资料夹内,首先在components内新增两个资料夹:

其中Home资料夹内建立index.js档,先简单放个文字进去就好:

src\components\Home\index.js

import React from 'react';

const Home = () => {
  return (
    <React.Fragment>
      <h1>Home</h1>
    </React.Fragment>
  );
};

export default Home;

一开始实作的总体经济的页面,要从App.js内独立出来,放在Macroeconomics资料夹内,App.js只留下控制路由的功能。

src\components\Macroeconomics\index.js

import React, { useState } from 'react';
import Charts from "../Charts/Charts";
import Selector from '../Selector/Selector';
import charts from '../../data/chart-collections.json';
import releases from '../../data/releases.json';
import sources from '../../data/sources.json';

const Macroeconomics = () => {
  const [filteredReleaseId, setFilteredReleaseId] = useState(0);
  const [filteredSourceId, setFilteredSourceId] = useState(0);

  const filteredCharts = charts.filter(chart => {
    let filterd = false
    if (filteredReleaseId === 0 && filteredSourceId === 0) { filterd = true }
    if (filteredReleaseId === 0 && filteredSourceId !== 0) {
      filterd = chart.source_id === filteredSourceId
    }
    if (filteredReleaseId !== 0 && filteredSourceId === 0) {
      filterd = chart.release_id === filteredReleaseId
    }
    if (filteredReleaseId !== 0 && filteredSourceId !== 0) {
      filterd = chart.release_id === filteredReleaseId && chart.source_id === filteredSourceId
    }
    return filterd
  });

  const releaseIdChangeHandler = (selectedReleaseId) => {
    setFilteredReleaseId(selectedReleaseId);
  };

  const sourceIdChangeHandler = (selectedSourceId) => {
    setFilteredSourceId(selectedSourceId);
  };

  return (
    <React.Fragment>
      <Selector
        selectedReleaseId={filteredReleaseId}
        selectedSourceId={filteredSourceId}
        releases={releases}
        sources={sources}
        onReleaseIdChange={releaseIdChangeHandler}
        onSourceIdChange={sourceIdChangeHandler}
      />
      <Charts charts={filteredCharts} />
    </React.Fragment>
  );
};

export default Macroeconomics;

新增路由控制元件

  • 路由资料:详细说明每一个路由对应的路径及元件...等资料。
    src\App-route.js

    import Home from "./components/Home/index";
    import Macroeconomics from "./components/Macroeconomics/index";
    
    //
    const routes = [
      {
        key: "route-home",
        name: "home",
        path: "/",
        withHeader: true,
        withFooter: true,
        public: true, // 若在维护开发中请设定 false
        authority: null,
        component: Home,
      },
      {
        key: "route-macroeconomics",
        name: "macroeconomics",
        path: "/macroeconomics",
        withHeader: true,
        withFooter: true,
        public: true, // 若在维护开发中请设定 false
        authority: null,
        component: Macroeconomics,
      }
    ];
    
    export default routes;
    
  • 路由层:将路由资料引入,并使用react-router-dom提供的元件撰写路由层

    src\routerLayer\index.js

    import React from "react";
    import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom";
    import routes from "../App-route";
    import Layout from "../layout";
    
    const RouterLayer = () => {
      return (
        <Router>
          <Switch>
            {routes &&
              routes
                .filter((r) => r.public)
                .map((route) => (
                  <Route exact key={route.key} path={route.path}>
                    <Layout {...route} />
                  </Route>
                ))}
          </Switch>
        </Router>
      );
    };
    
    export default RouterLayer;
    
  • Layout:将页面的基础设定统一处理,例如header/body/footer的设定

    src\layout\index.js

    import React from "react";
    import Header from "./header";
    import Body from "./body";
    
    const Layout = (props) => {
      return (
        <React.Fragment>
          <Header />
          <Body {...props} />
        </React.Fragment>
      );
    };
    
    export default Layout;
    

    Layout的header设定,网页的最上方是Navbar,因此直接拿来当header即可
    src\layout\header\index.js

    import React from "react";
    import Navbar from "../../components/Navbar/Navbar";
    
    const Header = () => {
      return <Navbar />
    }
    
    export default Header;
    

    Layout的body设定,这边先不对body做设定,直接导入component
    src\layout\body\index.js

    import React from "react";
    
    const Body = ({ component: Component }) => {
      return (
        <Component />
      );
    };
    
    export default Body;
    

    上面路由层的设定比较复杂一些,主要是因为想让程序可扩充性及可管理性高一些,例如只要调整header及body的index.js档案,就可以适用在各个路由的页面。

App.js引入路由层

上面的路由层写好之後,就可以导入App.js了,如下程序码,把整个路由架构写在路由层内之後,App.js就会变得非常简洁。

src\App.js

import React from 'react';
import './App.css';
import RouterLayer from "./routerLayer";

function App() {
  return (
    <div className="App">
      <RouterLayer />
    </div>
  );
}

export default App;

小结

本篇路由层参考其他专案架构,写出一个比较可以维护的资料夹结构,也很感谢工程师朋友愿意分享专案架构给我参考,跟React提供的basic版路由架构差蛮多的,学习到很多。下一篇就来制作首页的wireframe吧。


<<:  Day 17 - Error Handling 错误处理

>>:  [Day24] swift & kotlin 游戏篇!(6) 小鸡BB-游戏制作-线条绘制与弹跳动画

菜鸡用 Phaser 拾起童年游戏 30

嗨嗨嗨~大家好!到了我们铁人赛的最後一天了,也意味着我们将要分别了QQ 希望这些内容有让大家可以学习...

[REPORT] report rdl每页显示标题列

环境 VS2008 .rdl 1.新增报表 2.右键,新增table. 3.先设定title每页重覆...

Sass @mixin实现RWD DAY36

今天我们要来介绍 Sass Mixin 与 content的搭配 来解决RWD Scss: @mix...

[Day 30] 在 Dev's Ops 启程之後

Review 29 Days 在 Dev's Ops 启程之後,我们来回顾一下这三十天能有哪些精彩的...

Day 20 K-近邻演算法(KNN)

介绍完决策树和随机森林後,今天来介绍的是 K-近邻演算法(k-nearest neighbor cl...