redux和react路由系统(5和6)

React路由系统

1.组件路由

  1. yarn add react-router-dom

1.路由的简单使用

  1. HashRouter,BrowserRouter(react-router@6)
<!-- 在组件的顶层挂载了一个路由类型,其他地方无需挂载 -->
  <HashRouter>
    <!-- <BrowserRouter> -->
      <Routes>
          <Route path="/" element={<HomePage />} />
      </Routes>
    <!--  </BrowserRouter> -->
 </HashRouter>
  1. HashRouter,BrowserRouter(react-router@5)
  <!-- 在组件的顶层挂载了一个路由类型,其他地方无需挂载 -->
  <HashRouter>
    <!-- <BrowserRouter> -->
      <Route path="/" component={HomePage} />
    <!--  </BrowserRouter> -->
 </HashRouter>
  1. react-router@5中的页面堆叠问题
 <HashRouter>   
    <!-- exact精准匹配和Switch组件 -->
    <Switch>
       <Route exact path="/" component={HomePage} />
    </Switch>
     
 </HashRouter>
  1. 404页面(组件最后面)
<!-- react-router@6 -->
   <Route path="*" element={<h1>404</h1>} />
<!-- react-router@5 -->
   <Route path="*" render={()=><h1>404</h1>} />

2.路由传参(react-router@5)

  1. params参数
// 传递的参数
      //声明接收params 
      <Route path="/home/message/detail/:id/:title" component={
    
    Detail}/>
      //获取参数
      const {
    
    title,id}=this.props.match.params
  1. query参数
    // query参数,正常注册路由无需接收
    <Route path="/home/message/detail" component={
    
    Detail}/>
     //获取参数
    const {
    
    search}=this.props.location
    const {
    
    id,title}=qs.parse(search.slice(1))
  1. state参数
  // state参数 
 <Link to={
    
    {
    
    pathname:'/home/message/detail', state:{
    
    id:item.id,title:item.title}}}>{
    
    item.title}</Link>
  // 读取参数
 const {
    
    id,title}=this.props.location.state

3.路由传参(react-router@6)

(1)类组件获取参数
  1. 定义高阶组件withRouter
import React from "react";
import {
    
     NavigateFunction, useLocation, useNavigate, useParams } from "react-router";

export interface RoutedProps<Params = any, State = any> {
    
    
    location?: State;
    navigate?: NavigateFunction;
    params?: Params;
}


export function withRouter<P extends RoutedProps>(Child: React.ComponentClass<P>) {
    
    
    return (props: Omit<P, keyof RoutedProps>) => {
    
    
        const location = useLocation();
        const navigate = useNavigate();
        const params = useParams();
        return <Child {
    
     ...props as P } navigate = {
    
     navigate } location = {
    
     location } params = {
    
     params } />;
    }
}

  1. 类组件件中使用高阶组件修饰(接收参数)
import React from "react";
import {
    
     RoutedProps, withRouter } from "../../hoc/withRouter";

interface Props extends RoutedProps {
    
    }

class HomePage extends React.Component<Props> {
    
    
  constructor(props: Props) {
    
    
    super(props);
  }
  render(): React.ReactNode {
    
    
    // 获取params
    console.log(this.props.params);
    // 获取query
     console.log(this.props.location.search);
    return (
      <>
      </>
    );
  }
}

export default withRouter(HomePage);
  1. 类组件接收state参数
import React from "react";
import {
    
     RoutedProps, withRouter } from "../../hoc/withRouter";
import {
    
     Link } from "react-router-dom";

interface Props extends RoutedProps {
    
    }

class HomePage extends React.Component<Props> {
    
    
  constructor(props: Props) {
    
    
    super(props);
  }
  render(): React.ReactNode {
    
    
    // 接收state参数
    console.log(this.props.location.state);
    return (
      <Link to={
    
    `/1`} state={
    
    {
    
    id:1}}>home</Link>
    );
  }
}
export default withRouter(HomePage);
(2)函数组件获取参数
import {
    
     useParams, useLocation, useMatch } from "react-router-dom";

const HomePage: React.FC = () => {
    
    
  // params参数
  const params = useParams();
  // query参数和state参数
  const location = useLocation();
  // params参数
  const metch = useMatch("/:id");
  console.log(params.id, location.search, metch?.params);
  return <div>home</div>;
};

export default HomePage;

4.路由导航(react-router@5)

  1. 声明式导航
// push
   <Link push={
    
    true} to={
    
    `/`}>{
    
    item.title}</Link>
// replace
  <Link replace={
    
    true} to={
    
    `/`}>{
    
    item.title}</Link>
  1. 声明式导航
// 可以设置被选中的样式
// push
   <NavLink push={
    
    true} to={
    
    `/`}>push</NavLink>
// replace
  <NavLink replace={
    
    true} to={
    
    `/`}   activeClassName="selected">replace</NavLink>
  1. 编程式导航
// 1.push跳转+携带params参数
 props.history.push(`/b/child1/${
      
      id}/${
      
      title}`);
// 2.push跳转+携带search参数
props.history.replace(`/b/child1?id=${
      
      id}&title=${
      
      title}`);
// 3.push跳转+携带state参数
props.history.push(`/b/child1`, {
    
     id, title });
// 7.前进
this.props.history.goForward();
// 8.回退
this.props.history.goForward();
// 9.前进或回退 ( go )
this.props.history.go(-2); //回退到前2条的路由

5.路由导航(react-router@6)

(1)类组件的编程式导航
  1. 定义高阶组件withRouter
import React from "react";
import {
    
     NavigateFunction, useLocation, useNavigate, useParams } from "react-router";

export interface RoutedProps<Params = any, State = any> {
    
    
    location?: State;
    navigate?: NavigateFunction;
    params?: Params;
}


export function withRouter<P extends RoutedProps>(Child: React.ComponentClass<P>) {
    
    
    return (props: Omit<P, keyof RoutedProps>) => {
    
    
        const location = useLocation();
        const navigate = useNavigate();
        const params = useParams();
        return <Child {
    
     ...props as P } navigate = {
    
     navigate } location = {
    
     location } params = {
    
     params } />;
    }
}

  1. 类组件件中使用高阶组件修饰(跳转)
import React from "react";
import {
    
     RoutedProps, withRouter } from "../../hoc/withRouter";

interface Props extends RoutedProps {
    
    }

class HomePage extends React.Component<Props> {
    
    
  constructor(props: Props) {
    
    
    super(props);
  }
  render(): React.ReactNode {
    
    
    return (
      // 编程式跳转
       <button onClick={
    
    () => this.props.navigate("/2")}>跳转</button>
    );
  }
}

export default withRouter(HomePage);
(2)函数式组件编程跳转
import {
    
     useNavigate } from "react-router-dom";

const HomePage: React.FC = () => {
    
    
  const navigate = useNavigate();
  // push跳转+携带params参数
  navigate(`/b/child1/${
      
      id}/${
      
      title}`);
  // push跳转+携带search参数
  navigate(`/b/child2?id=${
      
      id}&title=${
      
      title}`);
  // push跳转+携带state参数
  navigate("/b/child2", {
    
     state: {
    
     id, title } });
  return <button onClick={
    
    () => navigate("/2")}>跳转</button>;
};

export default HomePage;

6.嵌套路由

  1. react-router@5的嵌套路由
<!-- react-router@5关闭精准匹配 -->
 <HashRouter>   
       <Route path="/" component={HomePage} />
       <!-- 二级路由 -->
       <Route path="/home" />
 </HashRouter>
  1. react-router@6的嵌套路由
<!-- 路由父组件 -->
 <BrowserRouter>
        <Routes>
          <Route path="/*" element={<HomePage />}></Route>
          <Route path="*" element={<h1>404</h1>} />
        </Routes>
</BrowserRouter>
<!-- 路由子组件中写 -->
<Routes>
     <Route path="/login" element={<h1>login</h1>} />
</Routes>
  1. 集中路由管理(嵌套路由)
<BrowserRouter>
        <Routes>
          <Route path="/" element={<Outlet />}>
            <Route path="/login" element={<LoginPage />} />
          </Route>
        </Routes>
      </BrowserRouter>

2. 配置路由

1.createBrowserRouter等

  1. 创建路由index文件
import {
    
     createBrowserRouter, Outlet } from "react-router-dom";

// Outlet子路由的出口文件
const router = createBrowserRouter([
  {
    
    
    path: "/",
    element: (
      <h1>
      
        <Outlet /> 
        111
      </h1>
    ),
    children: [
      {
    
    
        path: "login",
        element: <div>222</div>,
      },
    ],
  },
]);
export default router;

  1. 使用路由配置
import router from "./router";

function App() {
    
    
  return (
    <div className={
    
    styles.app}>
      <RouterProvider router={
    
    router} />
    </div>
  );
}

export default App;

2.useRoutes创建路由

  1. 创建路由index文件
import {
    
     Outlet, useRoutes } from "react-router-dom";

function BaseRouter() {
    
    
  const element = useRoutes([
    {
    
    
      path: "/",
      element: (
        <div>
          <Outlet />
          111
        </div>
      ),
      // 向Vue一样创建children放置页面
      children: [
        {
    
    
          path: "login",
          element: <h1>222</h1>,
        },
      ],
    },
  ]);
  return element;
}
export default BaseRouter;

  1. 使用路由配置
// 这里是组件首字符要大写
import BaseRouter from "./router";

function App() {
    
    
  return (
    <div className={
    
    styles.app}>
      <BrowserRouter>
        <BaseRouter></BaseRouter>
      </BrowserRouter>
    </div>
  );
}

export default App;

Redux全局状态管理

  1. yarn add redux

1. redux的基本使用

1. 读取redux中的数据

  1. 数据reducer目录
interface State {
    
    
  language: 'en' | 'zh'
  languageList: {
    
    label:string,key:string }[]
}

const defaultState: State = {
    
    
  language: 'zh',
  languageList: [
    {
    
    label:'中文',key:'zh'},
    {
    
    label:'English',key:'en'}
  ]
}

export default (state=defaultState, action: any) => {
    
    
  return state
}
  1. 引入数据目录导出state
import {
    
     createStore } from 'redux'
import LanReducer from './Reducer/LanReducer'

const store = createStore(LanReducer);

export default store;
  1. 组件中读取store数据
import store from "../../../store";
class HeaderClass extends React.Component<Props, State> {
    
    
  constructor(props: Props, state: State) {
    
    
    super(props);
    // 读取state中的数据
    const storeState=store.getState()
    this.state = {
    
    
      language: storeState.language ,// 当前语言
      languageList:storeState.languageList
    };
  }
  ....
}

2. 替换redux中的数据

  1. 数据reducer目录
interface State {
    
    
  language: string
  languageList: {
    
     label: string; key: string }[]
}

const defaultState: State = {
    
    
  language: 'zh',
  languageList: [
    {
    
     label: '中文', key: 'zh' },
    {
    
     label: 'English', key: 'en' },
  ],
}

export default (state = defaultState, action: any) => {
    
    
  switch (action.type) {
    
    
    // 切换语言
    case 'checkLanguage': {
    
    
      const newState = {
    
     ...state, language: action.payload }
      return newState
    }
    // 添加新语言
    case 'addLanguage': {
    
    
      const newlanguageList = [...state.languageList, action.payload]
      const newState = {
    
     ...state, languageList: newlanguageList }
      return newState
    }
    default:
      return state
  }
}

  1. 引入数据目录导出state
import {
    
     createStore } from 'redux'
import LanReducer from './Reducer/LanReducer'

const store = createStore(LanReducer);

export default store;
  1. 派发action数据
  // 点击切换语言
  checkLanguage = (e:any) => {
    
    
    const action = {
    
    
      type: "checkLanguage",
      payload:e.key
    }
    store.dispatch(action)
  }
  1. 在挂载的生命周期中进行订阅
  // 挂载
  componentDidMount() {
    
    
    store.subscribe(() => {
    
    
      const storeState = store.getState()
      this.setState({
    
    
        language: storeState.language
      })
    })
  }

3. redux的类型限制

  1. 创建action类型和创建action的工厂函数
export const CHECKLANGUAGE = 'checkLanguage'
export const ADDLANGUAGE = 'addLanguage'

interface changeLanguageAction {
    
    
  type: typeof CHECKLANGUAGE
  payload: string
}

interface addLanguageAction {
    
    
  type: typeof ADDLANGUAGE
  payload: {
    
     label: string; key: string }
}

export type languageActionTypes = changeLanguageAction | addLanguageAction

// 函数
export const changeLanguageActionCreator = (languageCode: string): changeLanguageAction => {
    
    
  return {
    
    
    type: CHECKLANGUAGE,
    payload: languageCode,
  }
}

export const addLanguageActionCreator = (label: string, key: string): addLanguageAction => {
    
    
  return {
    
    
    type: ADDLANGUAGE,
    payload: {
    
     label, key },
  }
}

  1. 修改reducer内容
import {
    
    CHECKLANGUAGE,ADDLANGUAGE,languageActionTypes} from './languageActions'

interface language {
    
    
  label: string
  key: string
}

interface State {
    
    
  language: string
  languageList: language[]
}

const defaultState: State = {
    
    
  language: 'zh',
  languageList: [
    {
    
     label: '中文', key: 'zh' },
    {
    
     label: 'English', key: 'en' },
  ],
}

export default (state = defaultState, action: languageActionTypes) => {
    
    
  switch (action.type) {
    
    
    // 切换语言
    case CHECKLANGUAGE: {
    
    
      const newState = {
    
     ...state, language: action.payload }
      return newState
    }
    // 添加新语言
    case ADDLANGUAGE: {
    
    
      const newlanguageList = [...state.languageList, action.payload]
      const newState = {
    
     ...state, languageList: newlanguageList }
      return newState
    }
    default:
      return state
  }
}


  1. 修改使用redux数据
import {
    
     changeLanguageActionCreator, addLanguageActionCreator } from '../../../store/language/languageActions'

 // 点击切换语言
  checkLanguage = (e: any) => {
    
    
    if (e.key === 'new') {
    
    
      store.dispatch(addLanguageActionCreator('新语言', 'new_lang'))
    } else {
    
    
      i18n.changeLanguage(e.key)
      store.dispatch(changeLanguageActionCreator(e.key))
    }
  }

2. react-redux实现派发和订阅

yarn add react-redux -S

  1. 入口文件中注入stroe注入
...
import {
    
     Provider } from 'react-redux'
import store from './store'

ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
  <React.StrictMode>
    {
    
    /* 注入属性 */}
    <Provider store={
    
    store}>
      <App />
    </Provider>
  </React.StrictMode>,
)

1. 用react-redux完成对类组件的订阅以及初始化

  1. store入口文件中导出state的类型
import {
    
     createStore } from 'redux'
import LanReducer from './language/LanReducer'

const store = createStore(LanReducer)

export type RootState = ReturnType<typeof store.getState>

export default store

  1. 使用高阶组件修饰完成订阅
...
import store, {
    
     RootState } from '../../../store'
import {
    
     connect as withConnect } from 'react-redux'

interface Props {
    
    }

// Props类型
type PropsType = Props &
  ReturnType<typeof mapStateToProps>
// 完成订阅(以及初始化,值会放入props中)
const mapStateToProps = (state: RootState) => {
    
    
  return {
    
    
    language: state.language,
    languageList: state.languageList,
  }
}

class HeaderClass extends React.Component<PropsType> {
    
    
  constructor(props: PropsType) {
    
    
    super(props)
  }
 ...
  render(): React.ReactNode {
    
    
    const navigate = this.props.navigate as NavigateFunction
    const {
    
     t } = this.props

    return (
   ...  
  //  值从props中取
           <Menu
          items={
    
    [...this.props.languageList, {
    
     label: '添加新语言', key: 'new' }]}
          onClick={
    
    (e) => this.checkLanguage(e)}></Menu>
             
    ...        
    )
  }
}

export const Header = withConnect(mapStateToProps, mapDispatchToProps)(HeaderClass)

2. 用react-redux完成对类组件的派发

  1. 完成派发的数据定义
...
import store, {
    
     RootState } from '../../../store'
import {
    
     changeLanguageActionCreator, addLanguageActionCreator } from '../../../store/language/languageActions'
import {
    
     connect as withConnect } from 'react-redux'
import {
    
     Dispatch } from 'redux'

interface Props {
    
    }

// Props类型
type PropsType = Props &
  ReturnType<typeof mapDispatchToProps> &
  
...
// 完成数据修改
const mapDispatchToProps = (dispatch: Dispatch) => {
    
    
  return {
    
    
    checkLanguage: (label: string) => {
    
    
      dispatch(changeLanguageActionCreator(label))
    },
    addLanguage: (label: string, key: string) => {
    
    
      dispatch(addLanguageActionCreator(label, key))
    },
  }
}
class HeaderClass extends React.Component<PropsType> {
    
    
  constructor(props: PropsType) {
    
    
    super(props)
  }
  ...
  render(): React.ReactNode {
    
    ... }
}

export const Header = withConnect(mapStateToProps, mapDispatchToProps)(HeaderClass)

  1. 修改点击修改语言
 // 点击切换语言
  checkLanguage = (e: any) => {
    
    
    if (e.key === 'new') {
    
    
      this.props.addLanguage('新语言', 'new_lang')
    } else {
    
    
      i18n.changeLanguage(e.key)
      this.props.checkLanguage(e.key)
    }
  }

3. redux toolkit简化redux

  1. 介绍
   Redux Toolkit 允许在 reducers 中编写 "mutating" 逻辑。

   它实际上并没有改变 state,因为使用的是 Immer 库,检测到“草稿 state”的变化并产生一个全新的

   基于这些更改的不可变的 state。
  1. 语言数据的模块
interface language {
    
    
  label: string
  key: string
}

interface State {
    
    
  language: string
  languageList: language[]
}

import {
    
     createSlice, configureStore } from '@reduxjs/toolkit'

const LanguageSlice = createSlice({
    
    
  name: 'language',
  initialState: {
    
    
    language: 'zh',
    languageList: [
      {
    
     label: '中文', key: 'zh' },
      {
    
     label: 'English', key: 'en' },
    ],
  },
  reducers: {
    
    
    checkLanguage(state: State, action: {
     
      payload: any; type: language | string }) {
    
    
      state.language=action.payload
    },
    addLanguage(state: State, action: {
     
      payload: any; type: language | string }) {
    
    
      state.languageList.push(action.payload)
    },
  },
})

export const {
    
     checkLanguage, addLanguage } = LanguageSlice.actions

export const language = configureStore({
    
    
  reducer: LanguageSlice.reducer,
})


  1. 引入数据的主模块
import {
    
     language } from './Reducer/LanReducer'

const store = {
    
    
  language,
}
export default store

1. 读取redux中的数据

  1. 读取数据
import store from '../../../store'

interface Props extends RoutedProps {
    
    }
interface State {
    
    
  language: string
  languageList: {
    
     label: string; key: string }[]
}
class HeaderClass extends React.Component<Props, State> {
    
    
  constructor(props: Props, state: State) {
    
    
    super(props)
    // 获取当前的数据
    const storeState = store.language.getState()
    this.state = {
    
    
      language: storeState.language, // 当前语言
      languageList: storeState.languageList,
    }
  }
  render(): React.ReactNode {
    
    
     ...
}
}
export const Header = withRouter(HeaderClass)

  1. 数据订阅
import store from '../../../store'

interface Props extends RoutedProps {
    
    }
interface State {
    
    
  language: string
  languageList: {
    
     label: string; key: string }[]
}
class HeaderClass extends React.Component<Props, State> {
    
    
  constructor(props: Props, state: State) {
    
    
   ....
  }
  // 挂载订阅(构造器中不能再次初始化state)
  componentDidMount() {
    
    
    store.language.subscribe(() => {
    
    
      const storeState = store.language.getState()
      this.setState({
    
    
        language: storeState.language,
        languageList: storeState.languageList,
      })
    })
  }
  render(): React.ReactNode {
    
    
     ...
}
}
export const Header = withRouter(HeaderClass)

2. 修改redux中的数据

  1. 简单介绍
 在store对应的模块中回应对于的方法

 在派发中传递过去的值变成的action的形式

 const action = {
    
    type: 'checkLanguage',payload: e.key}
  1. 派发对应的函数
import store from '../../../store'
import {
    
     checkLanguage, addLanguage } from '../../../store/lanReducer'

interface Props extends RoutedProps {
    
    }
interface State {
    
    
  language: string
  languageList: {
    
     label: string; key: string }[]
}
class HeaderClass extends React.Component<Props, State> {
    
    
  constructor(props: Props, state: State) {
    
    
    ....
  }
  // 挂载订阅(构造器中不能再次初始化state)
  componentDidMount() {
    
    
   ....
  }
  // 点击切换语言
  checkLanguage = (e: any) => {
    
    
    if (e.key === 'new') {
    
    
      store.language.dispatch(addLanguage({
    
     label: '新语言', key: 'new_lang' },))
    } else {
    
    
      store.language.dispatch(checkLanguage(e.key))
    }
  }
  render(): React.ReactNode {
    
    
     ...
}
}
export const Header = withRouter(HeaderClass)

猜你喜欢

转载自blog.csdn.net/qq_45897636/article/details/127622305