React + TypeScipt + reduxjs/toolkit手敲历史标签页
历史标签页是用户在主页经过的历史路由,这个路由会在菜单导航中用到,也在我们的历史标签组件中用到,也可以别的组件也会用到,所以这里最好使用redux来保存,但是redux用起来比较繁琐,所以我选择了reduxjs/toolkit最佳实践来写。
步骤
- 安装插件
- 在src目录下建好相关文件
- 定义数据
- 定义reduce函数
- 写历史标签组件
第一步
安装@reduxjs/toolkit
第二步
建好store目录 features用来写各种不同功能的store
index是汇总出口文件
第三步
历史数据是一个有value属性和router属性的数组,用来保存路由名字与路径
export interface tagState {
value: string;
router: string
}
export interface IHistory{
historyList : tagState[]
}
const initialState = {
historyList : [{
value : "首页",
router : "/home"
}]
}
第四步
increseHistory是添加历史路由
deleteHistory是删除历史路由
initHistory是初始化历史路由
注意typecript的导出方式
export const historySlice = createSlice({
name : "history",
initialState,
reducers:{
increaseHistory: (state, {payload}) => {
const isint = state.historyList.some(item => {
return item.router === payload.value.router
})
if(!isint){
state.historyList.push(payload.value)
}
},
// 定义一个减的方法
deleteHistory: (state, {payload}) => {
console.log(state)
state.historyList.forEach((item, index) => {
if(item.router === payload.value){
state.historyList.splice(index, 1)
}
})
},
initHistroy : (state, {payload}) =>{
state.historyList = payload.value
}
}
})
export const { increaseHistory, deleteHistory,initHistroy } = historySlice.actions;
// 默认导出
export default historySlice.reducer;
index.ts文件
import { configureStore } from "@reduxjs/toolkit";
import counterSlice from "./features/counterSlice";
import historySlice from "./features/historySlice";
// configureStore创建一个redux数据
const store = configureStore({
// 合并多个Slice
reducer: {
counter: counterSlice,
history: historySlice
},
});
export default store;
第⑤步
在历史标签页组件,样式自己定义,然后把这些数据和自己的menu菜单进行绑定就可以了,注意在删除历史标签的时候,事件会冒泡到父元素,navigate会冲突,所以要阻止冒泡。
import React, { useEffect} from "react";
import { useNavigate, useLocation } from 'react-router-dom';
import { useSelector, useDispatch } from 'react-redux';
import { deleteHistory,initHistroy } from '../../store/features/historySlice';
import {
CloseOutlined
} from '@ant-design/icons';
import "./index.css"
export interface tagState {
value: string;
router: string
}
const HistoryTags: React.FC = () => {
//获取路由
const locationPath = useLocation()
const navigate = useNavigate()
//获取state里面的历史路由
const { historyList } = useSelector((store: any) => store.history)
const dispatch = useDispatch()
//获取浏览器缓存中的历史路由,并初始化到state中
useEffect(() => {
const storeHistory = JSON.parse(sessionStorage.getItem("historyList") || '[]')
dispatch(initHistroy({value: storeHistory}))
},[])
// 将历史路由保存到浏览器中
useEffect(() => {
window.addEventListener("beforeunload",() => {
sessionStorage.setItem("historyList", JSON.stringify(historyList))
})
}, [historyList])
//点击标签跳转路由
const navigateRouter = (path:string) => {
navigate(path)
}
//删除标签路由
const deleteRouter = (e:any, path:string) => {
//阻止冒泡
e.stopPropagation()
//如果删除的当前选中路由的话,就跳回首页
if(path === locationPath.pathname){
navigate("/home")
}
dispatch(deleteHistory({value : path}))
}
return (
<div className='history-list'>
{
historyList.map((item: tagState) => {
return (<div className={item.router === locationPath.pathname ? "active-tag-item" : "tag-item"} key={item.router} onClick={() => navigateRouter(item.router)}>
{item.value}
<span className={item.router !== '/home' ? 'tag-icon' : "icon-none"} onClick={(e) => deleteRouter(e, item.router)}>
<CloseOutlined/>
</span>
</div>)
})
}
</div>
)
}
export default HistoryTags;