React-4.2 React-router 小案例

本文通过React小案例介绍了如何使用React Router进行组件化的路由配置。在`router.js`中集中管理数据和路由,提高代码维护性。同时详细讲解了组件如Nav.js、inner.js(包括list.js和footer.js)以及404页面的组织结构,展示了一个完整的React应用路由设计思路。
摘要由CSDN通过智能技术生成

src

在这里插入图片描述

1. app.js

import React from 'react';
import Nav from './component/Nav';
// import { Switch } from 'react-router-dom';
import { Switch,Route } from 'react-router-dom';
import { router } from "./router/router";
// import Page404 from '../component/page404';



function App() {
  return (
    <div className="wrap">  
        {/* 配置头部路由跳转 */}
        <Nav></Nav>

        <Switch>
          {/* 循环配置路由,具体看router.js的配置内容 */}
          {
            router.map((item,index)=>{
              return (<Route
                        key={index}
                        path={item.path}
                        render={item.render}
                        exact={item.exact}
                      >

              </Route>)
            })
          }
            {/* 回忆原始写法:
            <Route path="/" exact render={()=>{
              return <IndexPage user={user} setUser={setUser} />
            }}/>
            <Route path="/about" exact component={AboutPage} /> */}
        </Switch>
        
    </div>
  );
}

export default App;

2. index.js

import React from 'react';
import ReactDOM from 'react-dom';
import "./index.css";

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

import App from './App';

ReactDOM.render(

  <BrowserRouter>
  <App />
  </BrowserRouter>,
  document.getElementById('root')
);

3. index.css

body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
    'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
    sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
a {
  text-decoration: none;
}
.wrap {
    margin: 0 auto;
    width: 800px;
    padding-top: 20px;
}
.nav {
  display: flex;
  border-bottom: 1px solid #000;
  height: 40px;
}
.nav a {
  flex: 1;
  font: 14px/38px "宋体";
  text-align: center;
  padding: 1px 1px 0;
  color: #000;
  height: 40px;
  margin-bottom: -1px;
}
.nav a.active {
  background: #fff;
  color: red;
  padding: 0;
  border: 1px solid #000;
  border-bottom: none;
}
.pageNav {
  display: flex;
  margin-top: 10px;
  border-top: 1px solid #000;
  padding-top: 5px;
  justify-content: center;
}
.pageNav a,
.pageNav span {
  margin: 0 3px;
  width: 28px;
  font: 14px/30px "宋体";
  text-align: center;
  color: #000;
  border: 1px solid red;
  color: red;
}
.pageNav span {
  padding: 1px;
  border: none;
  color: #000;
}

4. http.js 请求数据

import Axios from "axios"

const http = Axios.create({
    baseURL:"https://cnodejs.org/api/v1"
})

function getData(type,page){
    return http.get(`/topics?page=${page}&tab=${type}&limit=20`);
}

export default getData;

5. router文件夹

router.js

一个一个写NavLink或者Link较繁琐,且不利于后期修改维护,所以把数据全部提取出来到router.js里,然后从router.js里遍历数据

import React from "react";
import {Redirect} from "react-router-dom";
import Inner from "../component/inner";
import Page404 from "../component/page404";
const types = ["all","good","share","dev","ask","job"]
const nav = [
    {
        url: "/all",
        exact: true,
        txt: "全部"
    },{
        url: "/good",
        exact: true,
        txt: "精华"
    },{
        url: "/share",
        exact: true,
        txt: "分享"
    },{
        url: "/ask",
        exact: true,
        txt: "问答"
    },{
        url: "/job",
        exact: true,
        txt: "招聘"
    },{
        url: "/dev",
        exact: true,
        txt: "客户端测试"
    }
];
const router = [
    // 1.重定向
    {
        path:"/",
        exact: true,
        render:(props)=>{
            return <Redirect to="/all" />;
        }
    },
    // 2.type和page,也即等于改变页码时
    {
        path: "/:type/:page",
        exact: true,
        render:(props)=>{
            console.log(props);
            let {type,page} = props.match.params; //接收动态路由传来的参数

            // 判断是否 已有
            if(types.includes(type)&&page>0){
                return <Inner {...props} />;
            }
            return <Page404 />; //错误路径的判断
        }
    },
    // 3.只点击变换type类型时
    {
        path: "/:type",
        exact: true,
        render:(props)=>{
            let {type} = props.match.params;
            if(types.includes(type)){
                return <Redirect to={`/${type}/${JSON.parse(sessionStorage.getItem(type)) || 1}`}  />;
            }
            return <Page404 />;
        }
    },
    // 4.没有匹配路由时
    {
        path: "",
        exact: false,
        render:()=>{
            return <Page404 />;
        }
    }
];
export {router,nav};

6. component文件夹

6.1 Nav.js 顶部导航

import React from "react";
import {NavLink, useLocation} from "react-router-dom";
import { nav } from "../router/router";

// 循环创建NavLink,配置头部路由跳转

function Nav(){

    let {pathname} = useLocation();
    // console.log(pathname);
    
    pathname = pathname.split("/");
    // console.log(pathname); //["" "job" "1"]

    return (
        <nav className="nav">
            {
                nav.map((item,index)=>{

                    let {url} = item;
                    url = url.split("/")
                    return(<NavLink
                        to={item.url}
                        key={index}
                        exact={item.exact}
                        activeClassName="active"
                        isActive={()=>{
                            return url[1] === pathname[1]
                        }}

                    >{item.txt}</NavLink>)
                })
            }
        </nav>
    );
}

export default Nav;

6.2 inner.js 列表显示区

import React from "react"
import List from "./list"
import { useState,useEffect,Fragment } from "react"
import getData from "../http"
import { useParams } from "react-router-dom"
import Footer from "./footer"


export default function Inner(){

    let {type,page} = useParams(); //动态路由
    let [data,setdata] = useState([]);

    let [isLoad,setLoad] = useState(false);

    useEffect(() => {
        if(!isLoad){
            getData(type,page).then((res)=>{
                console.log(res);
                // console.log(type);
                // console.log(page);
                setdata(res.data.data); //使data更新为新获取的值,从而渲染改变页面
                setLoad(true); //获取完毕后,把isLoad变为true,则不再重新去获取值
            });
        }
    }, [isLoad])

    useEffect(() => {
        setLoad(false)
        // 页码存储功能 -- 存 *** 在切换导航或者切换页码时进行存储,临时存储sessionStorage
        sessionStorage.setItem(type,JSON.stringify(page)) 
    }, [type,page]) //随着type,page的变化,而去改变isLoad的布尔值,从而操控是否去获取相应的新数据

    return(
        <div>
            {
                (!isLoad) ? (<div>数据请求中</div>) 
                          : (<Fragment>
                                <List data={data}></List>
                                <Footer />
                            </Fragment>)
            }
            
        </div>
    )

}
list.js 中间内容显示区
import React from "react"

export default function List(props){
    let {data} = props;
    // console.log(data);//Array(20)  是有id值,title等等值
    return(
        <ul>
            {
                data.map((item,index)=>{
                    return(<li
                            key={item.id}
                        >
                        {item.title}
                    </li>)
                })
            }
        </ul>
    )

}
footer.js 底部页码区
import React from "react"
import { Link, useParams } from "react-router-dom";

export default function Footer(){
    let {type,page} = useParams();

    // 页码长度
    let pageLength = 10;
    // 页码存储功能 -- 取 *** 在使用页码的位置取数据
    let pageStart =JSON.parse(sessionStorage.getItem(type)) - 5 ||  page - 5; //减几都是自定义的,减5意思是点中的页码位置前面一直放5个按钮,pageStart在这里定义的是第一个页码的页数,

    // 加一个安全判断
    pageStart = pageStart<1 ? 1: pageStart;
    pageStart--; // 先减一,因为下面循环遍历时需要逐步加1,但循环的第一个是不需要加的,所以这里先减1

    return (<nav className="pageNav">

        {
            [...(".".repeat(pageLength))].map((item,index)=>{
                pageStart++;
                if(pageStart == page){ // 当增加到所对应按下的数据时,令返回一个span,从而通过css来区别样式
                    return <span key={index}>{pageStart}</span>
                }else{// 不相等——说明这个不是选中的页面,需要他是拥有跳转功能的Link标签,跳转时的地址就是我们接收的,只需要改变页码就可以了
                    return <Link key={index} to={`/${type}/${pageStart}`}>{pageStart}</Link>
                    
                }
            })
        }

    </nav>)

}

6.3 page404.js

import React from "react";

export default function Page404(){
    return <div>页面飞走了</div>
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值