React + TypeScipt + reduxjs/toolkit手敲历史标签页

476 阅读2分钟

React + TypeScipt + reduxjs/toolkit手敲历史标签页

历史标签页是用户在主页经过的历史路由,这个路由会在菜单导航中用到,也在我们的历史标签组件中用到,也可以别的组件也会用到,所以这里最好使用redux来保存,但是redux用起来比较繁琐,所以我选择了reduxjs/toolkit最佳实践来写。

步骤

  1. 安装插件
  2. 在src目录下建好相关文件
  3. 定义数据
  4. 定义reduce函数
  5. 写历史标签组件

第一步

安装@reduxjs/toolkit

第二步

建好store目录 features用来写各种不同功能的store index是汇总出口文件 image.png

第三步

历史数据是一个有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;