zoukankan      html  css  js  c++  java
  • umi 如何使用 Mock 模拟数据

    用 umi 搭建的 react 项目中,看 package.json 文件,我们可以看到:

      "dependencies": {
        "dva": "^2.6.0-beta.6",
        "antd": "^3.19.5",
        "react": "^16.8.6",
        "react-dom": "^16.8.6"
      },

    其实 umi 中就使用了 dva 。

    先看一下目录结构,我会标注出需要用到的文件:

    ├── dist/  // 默认的 build 输出目录
    ├── mock/  // mock 文件所在目录,基于 express
    ├── config/
        ├── config.js  // umi 配置,同 .umirc.js,二选一
    └── src/  // 源码目录,可选
        ├── layouts/index.js  // 全局布局
        ├── models  // 全局的数据仓库 类似于 redux
        ├── pages  // 页面目录,里面的文件即路由
            ├── myPage  // 我创建的第一个文件夹
                ├── index.js  // 入口文件
                ├── index.less
                └── model.js  // 页面级别的数据仓库,相当于 页面级别的 redux
            ├── .umi  // dev 临时目录,需添加到 .gitignore
            ├── .umi-production  // build 临时目录,会自动删除
            ├── document.ejs  // HTML 模板
            ├── 404.js  // 404 页面
            ├── page1.js  // 页面 1,任意命名,导出 react 组件
            ├── page1.test.js  // 用例文件,umi test 会匹配所有 .test.js 和 .e2e.js 结尾的文件
            └── page2.js  // 页面 2,任意命名
        ├── services
            └── api.js  // *放接口
        ├── utils
            ├── config.js  // *配置路径
            └── request.js  // *封装 fetch 方法
        ├── global.css  // 约定的全局样式文件,自动引入,也可以用 global.less
        ├── global.js  // 可以在这里加入 polyfill
        ├── app.js  // 运行时配置文件
    ├── .umirc.js  // umi 配置,同 config/config.js,二选一
    ├── .env  // 环境变量
    ├── .gitignore  // 避免将不必要的代码提交到 git 仓库中
    └── package.json

    如果你做的是一个新项目,请不要跳过第一步。

    一、fetch 请求简单的封装

    1、在 utils 文件夹下创建 config.js 文件,utils/config.js ,对fetch请求路径进行配置

    //config.js文件
    
    const config = {
      apiUrl: process.env.NODE_ENV === 'development' ? ' http://127.0.0.1:7001' : 'https://www.baidu.com',
      apiPrefix: ' http://127.0.0.1:7001',
      proxy: true  //是否开启mock代理
    };
    
    export default config;

    2、简单封装 fetch 请求,utils文件夹下的 request.js 文件

    //request.js文件
    
    import fetch from 'dva/fetch';
    import config from './config';
    
    function parseJSON(response) {
      return response.json();
    }
    
    function checkStatus(response) {
      if (response.status >= 200 && response.status < 300) {
        return response;
      }
    
      const error = new Error(response.statusText);
      error.response = response;
      throw error;
    }
    
    const assyParams = (obj) => {
      let str = ''
      for (let key in obj) {
        const value = typeof obj[key] !== 'string' ? JSON.stringify(obj[key]) : obj[key]
        str += '&' + key + '=' + value
      }
      return str.substr(1)
    }
    
    /**
     * 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 default function request(obj) {
      let url = '';
      let options = {
        method: obj.method,
        headers: {
          'Content-Type': 'application/json; charset=utf-8',
        },
        credentials: 'include'     //是否携带cookie,默认为omit不携带; same-origi同源携带; include同源跨域都携带
      };
      if (obj.method === 'GET' || obj.method === 'get') {
        url = (config.proxy ? obj.url : config.apiUrl + obj.url) + '?' + assyParams(obj.data);
      }
      if (obj.method === 'POST' || obj.method === 'post') {
        url = config.proxy ? obj.url : config.apiUrl + obj.url;
        options.body = JSON.stringify(obj.data);
      }
      return fetch(url, options)
        .then(checkStatus)
        .then(parseJSON)
        .then(data => ({ data }))
        .catch(err => ({ err }))
    }

    二、写 api

    1、service 文件下创建 api.js

    import request from '../utils/request';
    export function getSomeData(params) {
        return request({
            method: "GET",
            url: `/appservice/common/v1/getSomeData`,
            data: JSON.stringify(params),
        })
    }

    三、mock 相关配置

    1、在 mock 文件夹下新建 someData.js 文件 (文件名看工作需要修改)

    const responseData = {
      status: 'ok',
      code: 200,
      data: "这是数据"
    }
    
    export default {
      // 支持值为 Object 和 Array
      'GET /appservice/common/v1/getSomeData': responseData,
    
      // GET POST 可省略 比如:
      '/api/users/1': { id: 1 },
    }

    四、编写 src/pages/myPage/model.js

    /*
    export default {
      namespace: '', // 表示在全局 state 上的 key
      state: {}, // 状态数据
      reducers: {}, // 管理同步方法,必须是纯函数
      effects: {}, // 管理异步操作,采用了 generator 的相关概念
      subscriptions: {}, // 订阅数据源
    };
    
    call: 执行异步函数
    put: 发出一个 Action,类似于 dispatch
    select: 返回 model 中的 state
    */
    
    import {
      getSomeData,
    } from '../../services/api';
    
    function initState() {
      return {
        modelNum: 0,
        text: "没有返回"
      };
    }
    
    export default {
      namespace: 'myPage', // 表示在全局 state 上的 key
      state: initState(), // 状态数据
      effects: { // 管理异步操作,采用了 generator 的相关概念
        *getSomeData({ payload }, { call, put, select }) {
          const res = yield call(getSomeData, payload);
          if (res.data.code === 200) { // 拿到数据,可以选择存到 model 中
            yield put({
              type: 'saveDefault',
              payload: {
                text: res.data.data
              },
            });
          }
          return res;
        },
      },
    
      reducers: { // 管理同步方法,必须是纯函数
        saveDefault(state, action) {
          return {
            ...state,
            ...action.payload,
          };
        },
    
        resetState() {   // 重置 state
          return initState();
        },
      },
    };

    五、调用api发送请求

    1、例如在 src/pages/myPage/index.js 页面发送请求,并在页面中显示请求到的数据

    2、如果在第4步中,选择将接口返回的数据存在 model 中,此页面就可以直接从 model 中获取数据,不需要存到 state 中

    import React, { Component } from "react";
    import { Button } from 'antd';
    import { connect } from 'dva';
    
    class secondPage extends Component {
      constructor(props) {
        super(props);
        this.state = {
          data: null
        }
      }
    
      getSomeData = async () => {
        const { dispatch } = this.props;
        await dispatch({
          type: 'myPage/getSomeData'
        }).then((res) => {
          if (res && res.data && res.data.code === 200) {
            this.setState({ // 这里选择将数据存在 state 中,也可以从 model 中获取
              data: res.data.data
            })
          }
        })
      }
    
      render() {
        const { data } = this.state;
        return (
          <div>
            <div>
              <span>异步请求的返回:{data || "--"}</span>
              <Button onClick={() => this.getSomeData()} >请求接口</Button>
            </div>
          </div>
        )
      }
    }
    
    const mapStateToProps = (model) => {
      console.log(model) // 查看 props 中的数据,可以拿到存在 model 中的数据。
    };
    
    export default connect(mapStateToProps)(secondPage)

    结尾:对于一个没人教的菜鸟来说,摸索出这一套,真的相当费劲,断断续续的隔了好几周,终于完成了。

    此文章复制可用,如果对你也有用,请一定要让我知道,万分感谢。

  • 相关阅读:
    需求分析与系统设计(二)阅读笔记
    阅读笔记:需求分析与系统设计(一)
    css方法div固定在网页底部
    阅读笔记:软件需求十步走(三)
    剑指offer 二维数组中的查找
    剑指offer 替换空格
    剑指offer 重建二叉树
    git常用操作
    关于 IO的同步异步间要描述
    svn-代码回滚
  • 原文地址:https://www.cnblogs.com/MrZhujl/p/13497272.html
Copyright © 2011-2022 走看看