看了很多遍react文档,同时也跟着文档写了好几次demo,心里觉得什么hooks也不过如此嘛,但总觉得不得劲,跟真实项目比,那些demo有点食之无味... 不知道有多少老哥跟我一样的心理->-<-。
这不趁着休息,(好吧是失业了。。。)想着这次一定要把react给拿下,于是有了这篇文章,首先声明,本人纯第一次写react,代码写的不好望大佬们海涵,本文旨在提供一个教程(如果可以称之为教程的话hhh)给没接触过react,或者是看过react文档却没有实战的同学。话不多说,正文开始。
介绍
本次项目是基于react18 + react-router-dom6 + antd5完成,布局是左右结构,左侧菜单完成了展开收缩、多层级嵌套展示、刷新记录展开菜单项等功能,右侧分为上下两部分,上部分为面包屑导航和个人信息展示,面包屑跟随路由变化,下面部分为内容区域,随点击菜单进行页面变化。具体如下Gif所示
准备
本次项目是直接通过create-react-app的方式创建,我把拉包的代码放一下,其他就不赘述了
js
npx create-react-app my-app
cd my-app
npm install --save react-router-dom
npm install antd --save
npm i
ok 其实也可以一次拉三个包,也可以用yarn,看你们自己就行。
开始撸
这个时候运行肯定大家都很熟悉啦
咱们把一些默认内容都删删,然后引入下antd组件看能否正常展示,可以的话就可以开始撸布局,路由啥的先不管。按各位喜欢的样子做就行,目前我是创建了一个layout文件放布局文件,具体的文件和页面如下所示:
antd组件的使用我就不赘述了,布局大致长这样,现在是全静态的。我们先来实现菜单栏的展开和收缩。其实就是一个变量的true/falseq切换而已,代码如下
js
const [collapsed, setCollapsed] = useState(false);
const toggleCollapsed = () => {
setCollapsed(!collapsed);
};
//在menu上有个属性inlineCollapsed
<Menu mode="inline" theme="dark" inlineCollapsed={collapsed} items={menuData} />
//接着在展开/收缩的icon上添加事件
<Button type="primary" shape="circle" onClick={toggleCollapsed}> {collapsed ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />} </Button>
此时,展开收缩完成。接下来就是进行点击菜单进行路由的切换了。我们引入react-router-dom,很多小的demo教程都是直接在文件里写路由,我们这是正式项目来的嘛,就直接抽出来哈,创建router文件,通过createBrowserRouter创建路由实例,然后你可以添加一些页面来跟路由进行匹配,这个时候我在官网看到的例子是这样的:
我此时心里想的是还挺方便,把<RouterProvider router={router} />
放到content那就完事了,事实上也确实是可以正常渲染的。此时的文件夹和页面如图所示:
一切都很完美是不是,接下来开始来做菜单点击事件。注意,坑要来了!!!!!
找到menu组件,添加onClick事件,然后通过router的文档找到跳转方法useNavigate,如下
js
import { useNavigate } from 'react-router-dom';
const navigate = useNavigate();
const handleMenuOnClick = (e) => {
const path = e.keyPath.reverse();
navigate(`/${path.join('/')}`);
};
<Menu mode="inline" theme="dark" inlineCollapsed={collapsed} items={menuData} onClick={handleMenuOnClick} />
写完之后一看,代码没报错,nice,然后切换到浏览器,wc怎么一片红,no
可以看到,错误是说 useNavigate() 这个方法必须在Router包裹的组件中才能使用
,我了个去,朋友们注意到了嘛,我们刚刚把RouterProvider
写在了content里,而现在是在slider侧边菜单使用useNavigate
,所以才导致的报错,为此我还发沸点问了掘金的大佬们,然后知道了如何修改,具体可以看xdm,初次尝试react,现在有这么个布局,希望在点击左侧菜单时对应展示右侧内...#掘金沸点# juejin.cn/pin/7327487...
好那咱们开始修改一下,首先把RouterProvider
放到index.js中,
js
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
//替换成
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<RouterProvider router={router} />
</React.StrictMode>
);
可以看到APP.js文件已经不需要了,然后页面也变成了这样 现在就能确保route在顶层,接下来你在项目哪里使用router的api都不会出问题了,但是还有一个问题就是布局全没了,没事,经过搜索我了解到,有一个Outlet组件类似vue-outer的router-view,但功能不完全一样,我们可以把页面的左右布局当作根布局,然后把菜单对应的页面当作子路由,由Outlet展示即可
,然后我们把APP.js中的内容移到layout文件夹中用一个新文件放置,然后把路由改造一下,具体如图:
终于恢复原样啦。还记得我们刚写的菜单点击事件嘛,试试吧,成功的感觉如此美妙!!!
但还没完,此时你会发现刷新页面后,菜单选中消失了,所以需要优化,这个时候需要用到useEffect,我们希望在页面初始化的时候通过路由来展开某项菜单,react-router提供了useLocation来获取路径信息,meun提供了这几个api可以做到设置菜单
代码如下
js
const navigate = useNavigate();
const location = useLocation();
useEffect(() => {
const { pathname } = location;
const pathArr = pathname.split('/');
setOpenKeys(pathArr);
setSelectKeys(pathArr.pop());
}, [location]);
const onOpenChange = (openKeys) => {
// console.log(openKeys);
setOpenKeys(openKeys);
};
const handleMenuOnClick = (e) => {
// console.log(e);
setSelectKeys(e.key);
const path = e.keyPath.reverse();
navigate(`/${path.join('/')}`);
};
<Menu mode="inline" theme="dark" inlineCollapsed={collapsed} items={menuData} openKeys={openKeys} selectedKeys={selectKeys} onClick={handleMenuOnClick} onOpenChange={onOpenChange} />
到这里,就可以进行点击切换菜单对应页面,以及刷新回显菜单栏的功能了,最后的面包屑回显和展示也是基于location来实现。
end
通过这次的练习,我也更加熟悉了react以及相关生态的使用,可能你们会说这so easy,但没关系,我确实学到了一些,也不惧怕react了。希望大家看了这篇文章也能动手敲敲,有问题可以评论区讨论哈~~