umi4全局dva

umi4的资料实在太少踩坑很多,希望可以帮助到你

1、安装 dva,react-redux

yarn add dva@latest -s

yarn add react-redux@latest -s

2、在src下 新建dva.js创建dva 实例

import { create } from 'dva-core';
// import { createLogger } from 'redux-logger';
import createLoading from 'dva-loading';
import { message } from 'antd';

// 1. 创建 dva 实例
const app = create({
  onError(e) {
    message.error(e.message, 3);
  },
});

// 2. 使用插件
// app.use(createLogger());
app.use(createLoading());

// 3. 注册模型
// app.model(require('./models/counter').default);

// 4. 导出 dva 实例
export default app;

3、在src下 新建models文件夹并在其下新建counter.ts

export default {
  namespace: "counter",

  state: {
    count: 0,
    token: "",
  },

  reducers: {
    add(state: {count: number}) {
      return {count: state.count + 1};
    },

    minus(state: {count: number}) {
      return {count: state.count - 1};
    },
    setToken(state: any, { payload: token }: any) {
      console.log(token,'storn')
      return {...state, token};
    },
  },

  effects: {},

  subscriptions: {},
};

4、在app.tsx中注入dva.js实例

import React from "react";
import {Provider} from "react-redux";
import app from "./dva";
// 初始化 dva
app.start();
export function render(oldRender: () => void) {
  oldRender();
}

export function rootContainer(
  container:
    | string
    | number
    | boolean
    | React.ReactElement<any, string | React.JSXElementConstructor<any>>
    | React.ReactFragment
    | React.ReactPortal
    | null
    | undefined
) {
  return React.createElement(

    React.createElement(Provider, {store: app._store, children: container})
  );
}

5、使用案例一、

import {connect} from "dva";
interface CounterProps {
  count: number;
  dispatch: Function;
}
const Counter: React.FC<CounterProps> = ({count, dispatch}) => (
  <div>
    <h2>{count}</h2>
    <button onClick={() => dispatch({type: "counter/add"})}>+</button>
    <button onClick={() => dispatch({type: "counter/minus"})}>-</button>
  </div>
);

export default connect(({counter}) => counter)(Counter);

 案例二,存储token

import {MenuFoldOutlined, MenuUnfoldOutlined} from "@ant-design/icons";
import {ProLayout} from "@ant-design/pro-layout";
import {connect} from "dva";
import {JSXElementConstructor, ReactElement, ReactFragment, ReactPortal, useEffect, useState} from "react";
import {history, Link, Outlet, useLocation, useSelectedRoutes} from "umi";
import proSettings from "./components/defaultSettings";
import setRightContentRender from "./components/rightContentRender";
import style from "./index.less";
import {handleRedirect} from "./msalConfig";
import defaultProps from "./_defaultProps";
interface CounterProps {
  dispatch: Function;
}
const BasicLayout: React.FC<CounterProps> = ({dispatch}) => {
  const [selectedKeys, setSelectedKeys] = useState<string[]>([]);
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  const [pathname, setPathname] = useState<any>("/login");
  const [collapsed, setCollapsed] = useState<boolean | undefined>(false);
  const routes = useSelectedRoutes();
  const lastRoute = routes.at(-1);
  // useEffect(() => {
  //   history.push(pathname);
  // }, [pathname]);
  useEffect(() => {
    handleRedirect().then(res => {
      if (res) {
        history.push("/home");
        dispatch({type: "counter/setToken", payload: res?.accessToken});
        console.log(res?.accessToken);
      }
    });
  }, []);

  // 自定义collapsed
  const CustomCollapsedButton = (val: boolean | undefined) => {
    const toggleCollapsed = () => {
      setCollapsed(!collapsed);
    };
    return val ? (
      <MenuUnfoldOutlined onClick={toggleCollapsed} className={style.collapsed} />
    ) : (
      <MenuFoldOutlined onClick={toggleCollapsed} className={style.collapsed} />
    );
  };

  const handleMenuSelect = ({key}: {key: string}) => {
    setSelectedKeys([key]);
  };
  // 将topmenu转为side
  interface TopMenu {
    type: "topmenu";
  }

  function convertTopMenuToTop(layout: TopMenu) {
    return {...layout, type: "side"};
  }

  const topMenu: TopMenu = {type: "topmenu"};
  const layout: any = proSettings.layout === "side" ? convertTopMenuToTop(topMenu) : proSettings.layout;

  if (lastRoute?.pathname === "/login") {
    return (
      <div>
        <Outlet />
      </div>
    );
  } else {
    return (
      <div>
        <ProLayout
          navTheme='light'
          style={{minHeight: "100vh"}}
          contentStyle={{margin: 0}}
          disableMobile // 是否禁用移动端模式
          layout={layout} // topmenu | mix | top
          fixSiderbar
          collapsed={collapsed}
          collapsedButtonRender={(val: boolean | undefined) => CustomCollapsedButton(val)} // 自定义collapsed 菜单展开/收起icon
          title='JIM'
          logo={
            <img
              onClick={() => {
                history.push("/home");
              }}
              className={style.img}
              src='https://gw.alipayobjects.com/zos/antfincdn/aPkFc8Sj7n/method-draw-image.svg'
              alt=''
            />
          }
          // 菜单
          {...defaultProps}
          location={{
            pathname,
          }}
          // 切换菜单
          menuItemRender={(
            menuItemProps: {isUrl: any; children: any; path: any},
            defaultDom:
              | string
              | number
              | boolean
              | ReactElement<any, string | JSXElementConstructor<any>>
              | ReactFragment
              | ReactPortal
              | null
              | undefined
          ) => {
            if (menuItemProps.isUrl || menuItemProps.children || !menuItemProps.path) {
              return defaultDom;
            }

            const isSelected = menuItemProps.path === lastRoute?.pathname; // 判断当前菜单项是否被选中
            const style = isSelected ? {color: "green"} : {}; // 根据选中状态动态添加样式

            return (
              <Link to={menuItemProps.path} style={style}>
                {defaultDom}
              </Link>
            );
          }}
          selectedKeys={selectedKeys}
          onSelect={handleMenuSelect}
          rightContentRender={setRightContentRender}
        >
          <div className={style.navs}>
            <Outlet />
          </div>
          {/* <div className={style.set}>设置</div> */}
        </ProLayout>
      </div>
    );
  }
};
export default connect(({counter}) => counter)(BasicLayout);

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jim-zf

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值