Umi+Dva入门

1_Dva、Umi初识

dva官网

umi官网

1.1_Dva在前端的位置

  1. 只有React可以做前端,但是数据的共享传输会是一个大问题
  2. 后来React+Redux可以让数据存在一个总的仓库中,并优化了数据的传输问题,但是对于异步的数据传输并没有解决
  3. 后来React+Redux+Redux-saga解决了异步的数据传输问题
  4. 后来React+Redux+Redux-saga+React-router
  5. 但是这么多技术太繁琐了,所以Dva诞生了,只需要React+Dva即可代替4

在这里插入图片描述

1.2_Umi作用

作用1:用于整合

在这里插入图片描述

作用2:用于自动配置路由

1.3_建立一个Umi项目

脚手架

先找个地方建个空目录。

$ mkdir myapp && cd myapp

通过官方工具创建项目,

$ yarn create @umijs/umi-app
Copy:  .editorconfigWrite: .gitignoreCopy:  .prettierignoreCopy:  .prettierrcWrite: .umirc.tsCopy:  mock/.gitkeepWrite: package.jsonCopy:  README.mdCopy:  src/pages/index.lessCopy:  src/pages/index.tsxCopy:  tsconfig.jsonCopy:  typings.d.ts

安装依赖

$ yarn
yarn install v1.21.1[1/4] 🔍  Resolving packages...success Already up-to-date.✨  Done in 0.71s.

启动项目

$ yarn start
Starting the development server...
✔ Webpack  Compiled successfully in 17.84s
 DONE  Compiled successfully in 17842ms                                       8:06:31 PM

  App running at:  - Local:   http://localhost:8000 (copied to clipboard)  - Network: http://192.168.12.34:8000

1.4_整理项目结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RAcJ0YFY-1668477438749)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20221026115136175.png)]

2_Dva详述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AMwAU5DF-1668477438750)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20221101181222138.png)]

2.1_Model模块

model就是存储数据、中转数据的仓库。

写法:

解释:action = {type,payload},type一般没用

effects = {put,call}

import { Effect, ImmerReducer, Reducer, Subscription } from 'umi';

const TryAModel = {
  namespace: 'tryamodel',

  state: {
    name: '',
  },
    /*
    effects 异步操作,经常用来和后端交互
    */
  effects: {
    *function_name(action:any, effects :any) {},
  },
      /*
      同步操作:经常用于仓库给各组件传值
      */
  reducers: {
    function_name(state,action) {}
    // 启用 immer 之后
    // save(state, action) {//state是旧值
    //   state.name = action.payload;
    //   newState = state
    //   return newState
    // },
  },
      
  subscriptions: {
      //如果路径名是'/'则调用function_name函数
    setup({ dispatch, history }:any) {
      return history.listen(({ pathname }:any) => {
        if (pathname === '/') {
          dispatch({
            type: 'function_name',
          });
        }
      });
    },
  },
};

export default TryAModel;

3_流程模板

3.1_组件模板

import connect from "umi";

const SecondExample = (props:any) =>{
  console.log(props.Model_SecondExampleModel)
  const clickTry = (props:any) =>{
    if (props.dispatch){
      props.dispatch({
        //路径:model的namespace+effects函数名
        type: 'Model_SecondExampleModel/getListFromServicesEffects',
        payload: {
          callback: (value: any) => {
            console.log(value);
          },
        },
      })
    }
    console.log(props.Model_SecondExampleModel)
  }
  return (
    <div>
      <a onClick={()=>{clickTry(props)}}>SecondExample</a>
    </div>
  );
}
//连接的参数名必须是model的namespace
export default connect(({ Model_SecondExampleModel }: any) => ({
  Model_SecondExampleModel,
}))(SecondExample);

3.2_Model(注意文件夹名是models且建在src下)

有两种方式

第一种会将数据存到仓库再返回

第二种会将数据直接返回

FirstExampleModel

import {Reducer, Effect, Subscription} from "umi";
/*
-----------------------------------------------------------------------------------------------------------------
本model用来演示正规的流程,即
①组件连接仓库;
②组件通过connect连接后给组件自动传的参数dispatch访问仓库中的异步函数effects;
③effects获取到数据后调用同步函数reducers存储数据到仓库state中
④组件自动更新参数并重新渲染
-----------------------------------------------------------------------------------------------------------------
 */


/*
-----------------------------------------------------------------------------------------------------------------
ts规范:对变量进行声明
 */
//对state声明,state用于仓库存储数据,也就是说state就是仓库
export type StateType = {
  list?: any[];
};
//对model声明
export type ExampleModelType = {
  namespace: string;
  state: StateType;
  effects: {
    getListFromServicesEffects: Effect;
  };
  reducers: {
    getListReducers: Reducer<StateType>;
  };
  subscriptions: {
    // setup: Subscription;
  }
};
/*
ts规范:对变量进行声明
-----------------------------------------------------------------------------------------------------------------
 */

/*
-----------------------------------------------------------------------------------------------------------------
model结构:namespace,state(仓库,用来存储数据),
effects异步处理,reducers同步操作(用于接收effects的结果并存到state中),subscription订阅(用于监听页面的跳转)
state变化后,连接此model的组件所接收到的参数会自动渲染
 */
const FirstExampleModel: ExampleModelType = {
  //本model唯一标识,命名标准:不能有'-',可以有'_',可以有大写
  //个人标准:以后都以'Model_'开头
  namespace: 'Model_FirstExampleModel',//Model_ExampleModel里面存的是state
  state: {
    list: [],
  },
  //命名规范(个人):函数功能+FromServices+Effects
  effects: {
    *getListFromServicesEffects({ payload }:any, { call, put }:any): Generator{//: Generator解决yield报红
      console.log("进入")
      const result:any = yield call(function,token,payload.value);
      yield put({
        type: 'getListReducers',
        payload: ['first'],
      });
      payload.callback('出来')//调用组件中的调用函数中的callback函数
    },
  },
  //命名规范(个人):函数功能+Reducers
  reducers: {
    getListReducers(state, {payload}) {
      //返回形式return {...state},必须是"...state",否则报错
      console.log(state)
      return {...state,list:payload};//将payload赋值给list
    },
  },

  subscriptions: {
    // setup({dispatch, history}: any) {
    //   return history.listen(({pathname}: any) => {
    //     if (pathname === '/') {
    //       dispatch({
    //         type: 'getListReducers',
    //       });
    //     }
    //   });
    // },
  }
};
/*
model结构
-----------------------------------------------------------------------------------------------------------------
 */


export default FirstExampleModel;

函数组件:FirstExample

import {connect} from "umi";

const FirstExample = (props:any) =>{
  console.log(props.Model_FirstExampleModel)
  const clickTry = (props:any) =>{
    if (props.dispatch){
      props.dispatch({
        //路径:model的namespace+effects函数名
        type: 'Model_FirstExampleModel/getListFromServicesEffects',
        payload: {
          callback: (value: any) => {
            console.log(value);
          },
        },
      })
    }
    console.log(props.Model_FirstExampleModel)
  }
  return (
    <div>
      <a onClick={()=>{clickTry(props)}}>FirstExample</a>
    </div>
  );
}
//连接的参数名必须是model的namespace
export default connect(({ Model_FirstExampleModel }: any) => ({
  Model_FirstExampleModel,
}))(FirstExample);

SecondExampleModel

import {Reducer, Effect, Subscription} from "umi";
/*
-----------------------------------------------------------------------------------------------------------------
本model用来演示简便的流程,即不通过reducers和state仓库直接在effects中返回
①组件连接仓库;
②组件通过connect连接后给组件自动传的参数dispatch访问仓库中的异步函数effects;
③effects获取到数据后调用callBack回调函数返回数据
④组件通过callback获取回调数据
-----------------------------------------------------------------------------------------------------------------
 */


/*
-----------------------------------------------------------------------------------------------------------------
ts规范:对变量进行声明
 */
//对state声明,state用于仓库存储数据,也就是说state就是仓库
export type StateType = {
  list?: any[];
};
//对model声明
export type ExampleModelType = {
  namespace: string;
  state: StateType;
  effects: {
    getListFromServicesEffects: Effect;
  };
  reducers: {
  };
  subscriptions: {
  }
};
/*
ts规范:对变量进行声明
-----------------------------------------------------------------------------------------------------------------
 */

/*
-----------------------------------------------------------------------------------------------------------------
model结构:namespace,state(仓库,用来存储数据),
effects异步处理,reducers同步操作(用于接收effects的结果并存到state中),subscription订阅(用于监听页面的跳转)
state变化后,连接此model的组件所接收到的参数会自动渲染
 */
const SecondExampleModel: ExampleModelType = {
  //本model唯一标识,命名标准:不能有'-',可以有'_',可以有大写
  //个人标准:以后都以'Model_'开头
  namespace: 'Model_SecondExampleModel',//Model_ExampleModel里面存的是state
  state: {
    list: [],
  },
  //命名规范(个人):函数功能+FromServices+Effects
  effects: {
    *getListFromServicesEffects({ payload }:any, { call, put }:any) : Generator{//: Generator解决yield报红
      console.log("进入")
      const result:any = yield call(function,token,payload.value);
      payload.callback(['second'])
    },
  },
  //命名规范(个人):函数功能+Reducers
  reducers: {
  },

  subscriptions: {
  }
};
/*
model结构
-----------------------------------------------------------------------------------------------------------------
 */


export default SecondExampleModel;

3.3_Service模板

import {
  methods,
  request,
  request_address_loacl,
} from '../request';//设置自己的request路径

const actions = {
  getStudentsList: {
    name: 'getStudentsList',
    url: '/class-studentinfo-s22-z2861/getAllStudentList',//后端接口
    source: 'local',
  },
  sendEmailToServer: {
    name: 'sendEmailToServer',
    url: '/class-studentinfo-s22-z2861/sendMail',
    source: 'local',
  }
};
const customRequest = ( action: any, formdata: any = null) => {
  let options: any = {
    headers: {
      'Content-Type': 'application/json;charset=utf-8',
      Accept: 'application/json'},
  };
  let url = action.url;
  switch (action.name) {
    case actions.getStudentsList.name:
      options['method'] = methods.get;
      break;
    case actions.sendEmailToServer.name:
      options['method'] = methods.post;
      options['body'] = JSON.stringify(formdata);
      break;
    default:
  }
  if (action.source == 'local') {
    return request(request_address_loacl + url, options);
  }
};

export function getStudentsList() {
  return customRequest(actions.getStudentsList);
}

export function sendEmailToServer(formdata: any) {
  console.log(formdata)
  return customRequest(actions.sendEmailToServer,formdata);
}

5_Request模板

在package.json中加入依赖"es6-promise": "^4.2.8"

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JTbvaYzK-1668477438751)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20221114191745011.png)]

//请求
// import fetch from 'dva';
require('es6-promise').polyfill();
require('isomorphic-fetch');

const serverDomain_loacl = 'http://10.1.40.84:7781';
export const request_address_loacl = serverDomain_loacl;

export const methods = {
  get: 'GET',
  post: 'POST',
  put: 'PUT',
  patch: 'PATCH',
  delete: 'DELETE',
};

export const assemble1QueryParams = (formdata: any) => {
  let url = '';
  let count = 0;
  Object.keys(formdata).map((value: any, index: any) => {
    // console.log(value);
    let key_temp = value;
    let value_temp = formdata[value];
    if (formdata[value]) {
      // console.log(formdata[value]);
      if (count == 0) {
        url = url + '?' + key_temp + '=' + value_temp;
      } else {
        url = url + '&' + key_temp + '=' + value_temp;
      }
      count++;
    }
  });
  return url;
};

function parseJSON(response: any) {
  // console.log(response.json());

  return response.json();
}

function checkStatus(response: any) {
  // console.log(response);
  if (response.status >= 200 && response.status < 300) {
    let token = response.headers.get('Authorization');
    if (token) {
      localStorage.setItem('token', token);
    }
    return response;
  } else {
    // console.log(response);

    // response.code = response.status;
    // response.msg = response.error;
    // console.log(response);

    return response;
  }
  // const error = new Error(response.statusText);
  // error.response = response.json();
  // // return error.response;
  // throw error;
}

/**
 * Requests a URL, returning a promise.
 *
 * @param  {string} url       The URL we want to request
 * @param  {object} [options] The options we want to pass to "fetch"
 * @return {object}           An object containing either "data" or "err"
 */
export function request(url: any, options: any) {
  console.log(url, options)
  return fetch(url, options)
    .then(checkStatus)
    .then(parseJSON)
    .then((data) => ({data}))
    .catch((err) => ({err}));
}

// .then(parseJSON)

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值