需要实现的效果
需要实现下面栏目固定,并且点击时切换到不同页面路由
实现过程
1.使用 prop-types 库进行类型检查
注意:自 React v15.5 起,React.PropTypes 已移入另一个包中。请使用 prop-types 库 代替。
PropTypes 提供了使用不同验证器的例子:
import PropTypes from 'prop-types';
MyComponent.propTypes = {
optionalArray: PropTypes.array,
optionalBool: PropTypes.bool,
optionalFunc: PropTypes.func,
optionalNumber: PropTypes.number,
optionalObject: PropTypes.object,
optionalString: PropTypes.string,
optionalSymbol: PropTypes.symbol,
optionalNode: PropTypes.node,
optionalElement: PropTypes.element,
optionalElementType: PropTypes.elementType,
optionalMessage: PropTypes.instanceOf(Message),
optionalEnum: PropTypes.oneOf(['News', 'Photos']),
optionalUnion: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
PropTypes.instanceOf(Message)
]),
optionalArrayOf: PropTypes.arrayOf(PropTypes.number),
optionalObjectOf: PropTypes.objectOf(PropTypes.number),
optionalObjectWithShape: PropTypes.shape({
color: PropTypes.string,
fontSize: PropTypes.number
}),
optionalObjectWithStrictShape: PropTypes.exact({
name: PropTypes.string,
quantity: PropTypes.number
}),
requiredFunc: PropTypes.func.isRequired,
requiredAny: PropTypes.any.isRequired,
customProp: function(props, propName, componentName) {
if (!/matchme/.test(props[propName])) {
return new Error(
'Invalid prop `' + propName + '` supplied to' +
' `' + componentName + '`. Validation failed.'
);
}
},
customArrayProp: PropTypes.arrayOf(function(propValue, key, componentName, location, propFullName) {
if (!/matchme/.test(propValue[key])) {
return new Error(
'Invalid prop `' + propFullName + '` supplied to' +
' `' + componentName + '`. Validation failed.'
);
}
})
};
安装依赖:
npm i prop-types -S
2.使用 useNavigate
v6 用 useNavigate 替代了 useHistory ,其返回了一个 navigate (点击查看用法) 的方法,实现比较简单:
- 从
NavigationContext 拿到 navigator ,也就是 history 实例。 - 然后根据
to、matches 的每项 pathnameBase 以及当前 URL pathname 生成最终的路径 path({pathname, search, hash}) - 根据是否指定
replace 来判断是调用 replace 还是 push 方法
import { useHistory } from 'react-router-dom';
function MyButton() {
let history = useHistory();
function handleClick() {
history.push('/home');
};
return <button onClick={handleClick}>Submit</button>;
};
现在,history.push() 将替换为 navigation() :
import { useNavigate } from 'react-router-dom';
function MyButton() {
let navigate = useNavigate();
function handleClick() {
navigate('/home');
};
return <button onClick={handleClick}>Submit</button>;
};
3.编写标签栏组件
新建 components/NavBar/index.jsx 文件,用于编写底部导航栏,代码如下所示:
import React, { useState } from 'react';
import PropTypes from 'prop-types'
import { TabBar } from 'zarm';
import { useNavigate, useLocation } from 'react-router-dom';
import CustomIcon from '../CustomIcon'
import s from './style.module.less';
const NavBar = ({ showNav }) => {
const location = useLocation()
const { pathname } = location
console.log('navbar pathname', pathname)
const [activeKey, setActiveKey] = useState(pathname);
const navigate = useNavigate()
const changeTab = (path) => {
setActiveKey(path)
navigate(path)
}
return (
<TabBar visible={showNav} className={s.tab} activeKey={activeKey} onChange={changeTab}>
<TabBar.Item
itemKey="/"
title="账单"
icon={<CustomIcon type="zhangdan" />}
/>
<TabBar.Item
itemKey="/data"
title="统计"
icon={<CustomIcon type="tongji" />}
/>
<TabBar.Item
itemKey="/user"
title="我的"
icon={<CustomIcon type="user" />}
/>
</TabBar>
);
};
NavBar.propTypes = {
showNav: PropTypes.bool
}
export default NavBar;
新建 components/NavBar/style.module.less 文件,用于编写底部导航栏样式,代码如下所示:
.tab {
border-top: 1px solid #e9e9e9;
}
4.使用标签栏组件
打开 App.jsx ,添加如下代码:
import React, { useState, useEffect } from 'react'
import NavBar from '@/components/NavBar';
import { Routes, Route, useLocation, BrowserRouter } from 'react-router-dom'
import { ConfigProvider } from 'zarm';
import routes from '../src/router'
function App() {
const location = useLocation()
const { pathname } = location
const needNav = ['/', '/data', '/user']
const [showNav, setShowNav] = useState(false)
useEffect(() => {
setShowNav(needNav.includes(pathname))
}, [pathname])
return <BrowserRouter>
<ConfigProvider primaryColor={'#007fff'}>
<Routes>
{
routes.map(route => <Route key={route.path} path={route.path} element={<route.component />}></Route>)
}
</Routes>
</ConfigProvider>
<NavBar showNav={showNav} />
</BrowserRouter>
}
export default App
我们发现报错了:Uncaught Error: You cannot render a <Router> inside another <Router>. You should never have more than one in your app.
这是因为想要在函数组件内执行 useLocation,该组件必须被 Router 高阶组件包裹,我们做如下改动,将 App.jsx 的 BrowserRouter 组件,前移到 main.jsx 内,如下:
App.jsx 里面
import React, { useState, useEffect } from 'react'
import NavBar from '@/components/NavBar';
import { Routes, Route, useLocation } from 'react-router-dom'
import { ConfigProvider } from 'zarm';
import routes from '../src/router'
function App() {
const location = useLocation()
const { pathname } = location
const needNav = ['/', '/data', '/user']
const [showNav, setShowNav] = useState(false)
useEffect(() => {
setShowNav(needNav.includes(pathname))
}, [pathname])
return <>
<ConfigProvider primaryColor={'#007fff'}>
<Routes>
{
routes.map(route => <Route key={route.path} path={route.path} element={<route.component />}></Route>)
}
</Routes>
</ConfigProvider>
<NavBar showNav={showNav} />
</>
}
export default App
main.jsx :
import React from 'react'
import ReactDOM from 'react-dom'
import { BrowserRouter } from 'react-router-dom'
import 'lib-flexible/flexible'
import './index.css'
import App from './App'
ReactDOM.render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>,
document.getElementById('root')
)
5.添加对应的页面路由
在 container 文件夹里添加下面三个模块的页面
import React from 'react'
const Home = () => {
return <div>账单</div>
}
export default Home
import React from 'react'
const Data = () => {
return <div>统计</div>
}
export default Data
import React from 'react'
const User = () => {
return <div>个人中心</div>
}
export default User
然后在 router/index.js 添加路由:
import Login from '@/container/Login'
import Home from '@/container/Home'
import Data from '@/container/Data'
import User from '@/container/User'
const routes = [
{
path: "/login",
component: Login
},{
path: "/",
component: Home
},{
path: "/data",
component: Data
},{
path: "/user",
component: User
}
];
export default routes
6.效果
我们可以切换到统计,然后刷新,发现也是没有问题。
参考资料
|