前面两章把基础简单介绍了,这一章开始就要正式搭建了,若有不正确的地方虚心接收大家的指正。

一、项目目录的介绍

思考了一下还是把自己的目录习惯介绍一下吧,这样大家看起来应该更容易理解一点,因为我自己经常也是看到别人文章没看到目录介绍,跟着写就发现了对不上的情况!

在第一章就介绍了初始化的文件目录,这里就不介绍当时介绍过的目录了,要是忘记了可以去第一章节回顾;

components:与vue一样放置组件使用

layout:顾名思义,这是一个布局文件夹

router:因为这是属于单页面应用,局部刷新就少不了这个文件夹里面的东西

store:这是redux的全局状态管理仓库文件夹

store/actions:封装操作状态的方法的文件夹

store/reducers:放置模块化

store/connect.js:封装统一的装饰器使用

store/index.js:状态管理器的主入口文件

 utils:放置一些工具函数

views:放置页面模块

二、封装状态管理器

关于这个我不做过多的赘述了,这个地方不知道的可以去参考我的另一个文章,传送门

就说下持久化保存吧,因为这里毕竟要用到

首先安装持久化的依赖

yarn add redux-persist

在store/index.js中使用

代码

import {createStore, combineReducers} from 'redux'

// redux的持久化保存
import {persistReducer, persistStore} from "redux-persist";
import storage from "redux-persist/lib/storage";

//创建reducer以及初始化状态
const reducer = (state = {
    count: 1
}, action) => {
    // action中type代表动作的标识,用于触发行为,payload代表传递的参数
    switch (action.type) {
        case 'ADD':
            return {...state, count: state.count + action.payload}
        case 'REDUCE':
            return {...state, count: state.count - action.payload}
        default:
            return state
    }
}

//定义配置的信息
const persistConfig = {
    key: "root",
    storage: storage,
    // 如果不想将部分state持久化,可以将其放入黑名单(blacklist)中.黑名单是设置
//   blacklist: ['ll']
}
//创建持久化的配置persist的信息
const persist_reducers = persistReducer(persistConfig, reducer);

//创建状态管理器
const store = createStore(persist_reducers)
const persistor = persistStore(store);

export {store, persistor}


这地方是还未做拆分的,后面会做reducer的拆分,方便管理;

在入口文件处需要设置

注:如果不知道这里的Provider是什么意思的可以去看我的《React-Redux使用connect,并封装装饰器》这个文章,里面是有写的

三、路由模块

这里的路由就可以采用router6.x的特性,有一个useRouter的HOOK,这个写法就相当于vue里面的路由,单独拆成一个json文件,这样就更加易于维护管理了;

但是不局限于这个方式,喜欢router5.x的也可以采用循环方式注册路由,这里就看个人的习惯;

在layout文件夹下面创建Home.jsx文件、在views下创建404.jsx和login.jsx;

然后在router下创建index.jsx文件,创建路由;

router/index.jsx

import React, {lazy ,Suspense} from "react";

const routes = [
    {
        path:'/',
        component:lazy(()=>import('@/layout/Home'))
    },
    {
        path:'/login',
        title:'登录',
        component:lazy(()=>import('@/views/login'))
    },
    {
        path:'*',
        title:'404',
        component:lazy(()=>import('@/views/404'))
    }
]

// 懒加载
const syncRouter = (table)=>{
    let mRouteTable=[]
    table.forEach((route)=>{
        mRouteTable.push({
            path:route.path,
            element:(
                <Suspense fallback={<div>路由加载中...</div>}>
                    <route.component />
                </Suspense>
            ),
            children:route.children&&syncRouter(route.children)
        })
    })
    return mRouteTable
}

export const newRoutes = syncRouter(routes)

然后在App.jsx文件中引入使用

最后在主入口文件main.jsx中引入注册

在网页上验证是否生效

输入错误的路由,进入了404的页面去了

到这里说明你的路由成功了

四、首页布局

 前面已经导入了antd5.x版本的组件了,所以这里可以直接按需引入使用antd的组件

这里采用的是这种布局方式

可以根据antd文档上的代码,写自己的业务需求

layout/Home.jsx

按照文档的代码复制进去,打开页面

现在已经把局布好了,但是这个点击左边右边并不会更新;那是因为路由并没有与这个页面关联起来,所以点击左边右边是不会切换刷新的;

五、路由与布局相关联

根据布局我们能看出,内容模块处于的不是一级路由,所以我们要创建子路由文件了;

在views文件夹下面创建测试的模块以及对应的jsx文件

在这里我创建了一个中间页面layout/LayoutPage.jsx;若熟悉vue的 朋友就可以看出这个的用处,多层嵌套使用这个占位;

接下来我们就需要把这个路由文件在redux中引入,做全局使用,并且把这个在封装一个在antd的Menus组件使用的数据,方便在布局页面直接使用,而且不会出现还未初始化成功的同步问题;

上图这个是我处理的菜单栏的数据,也可以直接根据需求把这个写成菜单json数据,我这里根据路由文件处理的是为了方便做动态路由,简单说说我这里怎么来处理的吧;

第一步:路由文件里面去调取redux的actions 

第二步:处理菜单栏

第三步:在布局组件里使用

这样就已经把菜单栏目配置好了,但是你会发现无论怎么切换嵌套路由地址依然不会变化,那是因为缺少占位的组件Outlet;

        今天看到一段话是这样描述outlet的。说的是嵌套路由,可以保证子路由共享父路由的界面而不会覆盖。为此React提供了Outlet组件,将其用于父组件中可以为子路由的元素占位,并最终渲染子路由的元素。

  这句话的意思大概就是说outlet是应用于嵌套路由的占位的。PS:如果是一级路由的话,我个人的理解还是要用Routes跟Route搭配的;

忘记说了,前面创建了一个占位组件LayoutPage.jsx  内部写法如下

到这一步的话就恭喜你已经可以通过地址栏更改路由了 

 到这里还没满足我们的需求,就是点击左边切换内容数据,那么该怎么做呢?

这里的话就要用到我们的路由跳转功能了,这里因为我们用的路由文件方式,那么就采用useNavigate这个方式跳转;

按照教程引入并使用: 

 

 点击菜单栏出现了下方的错

这是因为用的类组件方式,并不支持这种方式,那就要采用其他方式了,这里就需要包裹一层才能使用这个方式了;

layout/Home.jsx的修改成包裹方式导出

代码

const widthUseNavigate = (WrapCompontent)=>{
    // 设置别名
    WrapCompontent.displayName = `widthUseNavigate${getDisplayName(WrapCompontent)}`
    return function NavigateCompont() {
        const navigate = useNavigate()
        const location = useLocation()
        // 给传入的组件新增一个to方法,传给原始组件的props,在原始组件中通过this.props.to(参数)使用
        return <WrapCompontent to={navigate} location={location}></WrapCompontent>
    }
}

const getDisplayName = (WrapCompontent)=>{
    return WrapCompontent.displayname || WrapCompontent.name || 'Component'
}


// 使用高阶组件包裹当前类组件
const NavigateCompont = widthUseNavigate(Home);

然后再打印一下Home组件的props你就会发现,这里面又多出来很多东西

这样你就可以直接使用to方式跳转组件了;

 这里点击菜单栏获取到的参数里面有两个参数key、keyPath,根据这两个就可以组装跳转路由地址了

 这里只是做演示,具体的嵌套需要自己去处理

做到这步就可以点击左边然后右边跟随变化了,但是这里有一个需要自己去处理,就是通过this.props里面的location这个参数去获取当前的路由去做初次进来渲染左边默认选中的路由;

 

到这里就差不多结束了联动的操作了,这个章节的内容到这里就结束了,到这个章节的代码链接放在下面,需要的可以自行去看看,

传送门

 

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐