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';

 
         
 import { connect } from 'react-redux';
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 中的數據。
 return model.text // return 出來的數據,會被添加到對應的 props 中 }; export default connect(mapStateToProps)(secondPage)


/*

拿到 dispatch 的幾種方式
import { useDispatch } from 'react-redux';
import { useDispatch } from 'dva';

export default function (props) {
  const dispatch = useDispatch();
  return (
    <div>
     
    </div>
  );
}
*/ 
 

 

結尾:對於一個沒人教的菜鳥來說,摸索出這一套,真的相當費勁,斷斷續續的隔了好幾周,終於完成了。

此文章復制可用,如果對你也有用,請一定要讓我知道,萬分感謝。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM