ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

第七课之dva以及搭建常用界面

2020-11-29 20:04:59  阅读:287  来源: 互联网

标签:axios 界面 第七课 dva primary dispatch 组件 return payload


什么是redux

Redux 是 JavaScript状态容器,提供可预测化的状态管理,可以让你构建一致化的应用,运行于不同的环境(客户端、服务器、原生应用),并且易于测试

为什么用Redux

因为对于react来说,同级组件之间的通信尤为麻烦,或者是非常麻烦了,所以我们把所有需要多个组件使用的state拿出来,整合到顶部容器,进行分发

redux实现了什么

在react的数据交互理念中,只能进行父子组件的通信,无法想和谁通信就和谁通信,redux做到了将数据传递添加到了全局,任何地方都可以进行接收使用。

将需要修改的state都存入到store里,发起一个action用来描述发生了什么,用reducers描述action如何改变state树。创建store的时候需要传入reducer,真正能改变store中数据的是store.dispatch API

dva介绍

dva 首先是一个基于 redux 和 redux-saga 的数据流方案,然后为了简化开发体验,dva 还额外内置了 react-router 和 fetch,所以也可以理解为一个轻量级的应用框架。

数据流向

数据的改变发生通常是通过用户交互行为或者浏览器行为(如路由跳转等)触发的,当此类行为会改变数据的时候可以通过 dispatch 发起一个 action,如果是同步行为会直接通过 Reducers 改变 State ,如果是异步行为(副作用)会先触发 Effects 然后流向 Reducers 最终改变 State,所以在 dva 中,数据流向非常清晰简明,并且思路基本跟开源社区保持一致(也是来自于开源社区)

如图:

Models


import * as addbanner from '../services/addbanner';
export default {
  namespace: 'addbanner',
  state: {},
  subscriptions: {
    setup({ history, dispatch }, one rror) {
    }
  },
  effects: {
    //call:执行异步函数
    //put:发出一个 Action,更新store,类似于 dispatch
    *bannerlist(action, { call, put }) {
      const testRes = yield call(addbanner.bannerlist, action.params);
      yield put({
        type: 'test',
        payload: {
          bannerlistRes: testRes
        },
      });
    },
  reducers: {
    test(state, { payload }) {
      return {
        ...state,
        ...payload,
      };
    }
  },
};

State

State 表示 Model 的状态数据,通常表现为一个 javascript 对象(当然它可以是任何值);操作的时候每次都要当作不可变数据(immutable data)来对待,保证每次都是全新对象,没有引用关系,这样才能保证 State 的独立性,便于测试和追踪变化。

Action

Action 是一个普通 javascript 对象,它是改变 State 的唯一途径。无论是从 UI 事件、网络回调,还是 WebSocket 等数据源所获得的数据,最终都会通过 dispatch 函数调用一个 action,从而改变对应的数据。action 必须带有 type 属性指明具体的行为,其它字段可以自定义,如果要发起一个 action 需要使用 dispatch 函数;需要注意的是 dispatch 是在组件 connect Models以后,通过 props 传入的。

dispatch 函数

dispatching function 是一个用于触发 action 的函数,action 是改变 State 的唯一途径,但是它只描述了一个行为,而 dipatch 可以看作是触发这个行为的方式,而 Reducer 则是描述如何改变数据的。

在 dva 中,connect Model 的组件通过 props 可以访问到 dispatch,可以调用 Model 中的 Reducer 或者 Effects,常见的形式如

dispatch({
  type: 'user/add',
  payload: {}, // 需要传递的信息
});

Reducer

Reducer(也称为 reducing function)函数接受两个参数:之前已经累积运算的结果和当前要被累积的值,返回的是一个新的累积结果。该函数把一个集合归并成一个单值。

Effect

Effect 被称为副作用,在我们的应用中,最常见的就是异步操作。它来自于函数编程的概念,之所以叫副作用是因为它使得我们的函数变得不纯,同样的输入不一定获得同样的输出。

Subscription

Subscription 语义是订阅,用于订阅一个数据源,然后根据条件 dispatch 需要的 action。数据源可以是当前的时间、服务器的 websocket 连接、keyboard 输入、geolocation 变化、history 路由变化等等。

// 比如:当用户进入 /users 页面时,触发action users/fetch 加载用户数据。
subscriptions: {
    setup({ dispatch, history }) {
      history.listen(({ pathname }) => {
        debugger
        if (pathname === '/primary') {
          dispatch({
            type: 'primary/getmerProClassList',
          });
        }
      })
    }
}
dva redux
引用dva 要引入多个库,项目结构复杂
实现一个异步交互修改的文件很少 实现一个异步交互需要修改的文件太多,容易出错
使用方式清晰、便捷 使用方式复杂、繁琐

Router

这里的路由通常指的是前端路由,由于我们的应用现在通常是单页应用,所以需要前端代码来控制路由逻辑,通过浏览器提供的 History API 可以监听浏览器url的变化,从而控制路由相关操作。

import { Router, Route } from 'dva/router';
app.router(({history}) =>
  <Router history={history}>
    <Route path="/" component={HomePage} />
  </Router>
);

安装

npm install dva-cli -D

使用

  • 1.创建页面组件,文件以及组件命名大驼峰
  • 2.添加路由,按项目规则命名(eg:列表页面:/list,添加列表页面:/list/listAdd)
  • 3.定义model
  • 4.定义service以及api地址
  • 5.连接model和组件
1.创建页面组件Primary.js
import React, { Component } from 'react'

export default class Primary extends Component {
   render() {
      return (
         <div>
            Primary
         </div>
      )
   }
}

2.添加路由,并在福禄管家将对应菜单添加到自己的商户应用下,否则系统会进行控制,也是无法打开
const Primary = dynamic({
  app,
  models: () => [
    import('./models/primary'),
  ],
  component: () => import('./components/Primary')
});
// 使用
<Route exact path="/primary" render={(props) => WraperRouter(props, Primary)} />
3.创建model文件couponsList.js
import * as primary from '../services/primary';

export default {
  namespace: 'primary',
  state: {},
  effects: {
    *saveOneProClass({ payload, callback }, { call, put }) {
      const testRes = yield call(primary.saveOneProClass, payload);
      yield put({
        type: 'success',
        payload: {
          saveOneProClassResult: testRes
        }
      });
      if (callback instanceof Function) {
        callback(testRes);
      }
      return testRes;
    },
    *deleteProClass({ payload, callback }, { call, put }) {
      const testRes = yield call(primary.deleteProClass, payload);
      yield put({
        type: 'success',
        payload: {
          deleteProClassResult: testRes
        }
      });
      if (callback instanceof Function) {
        callback(testRes);
      }
      return testRes;
    },
    *getmerProClassList({ payload, callback }, { call, put }) {
      const testRes = yield call(primary.getmerProClassList, payload);
      yield put({
        type: 'test',
        payload: {
          getmerProClassListRes: testRes
        },
      });
      if (callback instanceof Function) {
        callback(testRes);
      }
      return testRes;
    },
  },
  reducers: {
    success (state, {payload}) {
      return {
        ...state,
        ...payload,
      };
    }
  }
}
4.创建service文件couponsList.js以及在api.js添加地址(查看后端服务地址进行配置)

请求的地址都从service.js进行传递

// 引入axios组件
import axios from '../utils/axios';
// 引用项目api地址
import Api from '../configs/api';
// get请求
export function getMerProClassOneList(params) {
  return axios.get(configs.host.test + Api.getMerProClassOneList, { 'params': params });
}

// post请求
export function saveOneProClass(params) {
  return axios.post(configs.host.test + Api.saveOneProClass,params);
}

export function deleteProClass(params) {
  return axios.get(configs.host.test + Api.deleteProClass, { 'params': params });
}

// put请求
// export function modifyMembershipInfo(params) {
//   return axios.put(configs.host.test + // Api.modifyMembershipInfo,params);
// }
// delete请求
// export function guessYouLikeDelete(params) {
//     return axios.delete(configs.host.test + Api.guessYouLike, { // 'params': params })
// }

axios.js

// axios.js用于处理数据请求响应(添加请求header,返回数据异常捕获等)
import axios from 'axios';
import { message } from 'antd';
import { handleErrCallBack } from 'fl-pro';

// axios.defaults.baseURL = '';  API 域。默认值:当前域
axios.defaults.withCredentials = true;  // 允许跨域且携带 Cookie(或自定义头)。默认值:false
axios.defaults.timeout = 30000; // 设置请求超时时间(ms)不超过半分钟
axios.defaults.headers.common['Authorization'] = '';  // 携带的自定义头
axios.defaults.headers.post['Content-Type'] = 'application/json';  // 设置请求提内容类型,其他可选值:application/x-www-form-urlencoded

axios.interceptors.request.use(config => {
  // console.log('【request】', config);
  config.headers["Authorization"] = `Bearer ${localStorage.getItem('access_token')}`;
  config.headers["MerchantId"] = localStorage.getItem('MerchantId');
  return config;
}, error => {
  // console.log('【request error】', error);
  return Promise.reject(error);
});

axios.interceptors.response.use(response => {
  return response.data;
},handleErrCallBack
);

export default axios;
5.api.js添加
getmerProClassList: '/api/product/GetMerProClassList',// 获取商户商品分类 //商品一级分类
saveOneProClass: '/api/product/SaveOneProClass', //添加编辑一级分类保存接口
deleteProClass: '/api/product/DeleteProClass', //删除分类
6.连接model和组件
// 方式一:直接在引用的地方连接
const Primary = dynamic({
  app,
  models: () => [
    import('./models/primary'),
  ],
  component: () => import('./components/Primary')
});



// 方式二:单页应用入口文件index.js添加引用

import { default as primary } from './models/primary';
app.model(primary);

// 区别: 在入口文件注册的model文件,可以在项目任何一个路由页面进行使用,而在单个路由注册的model文件只能在该页面使用,别的页面无法使用你的model
核心代码查看
  • 查询
// 查询公用函数
getData = () => {
   const { postData } = this.state;
   this.props.dispatch({ type: 'primary/getmerProClassList', payload: { ...postData } }).then((res) => {
      const { code, data } = res;
      if (code === '0') {
         return this.setState({
            tableData: data.list,
            total: data.total
         });
      }
      message.error(res.message);
   });
}
// 处理表单values并调用,查询
search = (err, value) => {
   //查询列表
   const { postData } = this.state;
   postData.pageIndex = 1;
   this.setState({
      postData: { ...postData, ...value }
   }, () => {
      this.getData();
   })
}
  • 新增、编辑
// 子组件弹窗,新增编辑一级分类代码
sureAdd = () => {
    this.props.form.validateFields((err, values) => {
        if (!err) {
            const param = values;
            const { iconPath, iconPathEdit, detailInfo } = this.state;
            let nowImgUrl = '';
            if (detailInfo.id) {
                param.id = detailInfo.id;
                // 如果用户上传了或者删除了
                if (iconPathEdit) {
                    nowImgUrl = iconPath ? iconPath.response.data : '';
                }
                else {
                    nowImgUrl = detailInfo.iconPath;
                }
            } else {
                nowImgUrl = iconPath ? (iconPath.flag ? iconPath.fileList[0].url :
                    iconPath.response.data) : '';
            }

            if (!nowImgUrl) {
                return message.error('请选择一级分类图!');
            }
            param.iconPath = nowImgUrl;
            this.props.dispatch({
                type: 'primary/saveOneProClass',
                payload: param,
                callback: ({ code, message: info }) => {
                    if (code === '0') {
                        this.props.getData();
                        this.handleClose();
                    } else {
                        message.error(info);
                    }
                }
            });
        }
    });
}

// 图片上传的回调
updateImg = (filed, value, fieldEdit) => {
    this.setState({
        [filed]: value,
        [fieldEdit]: true
    });
}
// 封装的上传图片组件
<UploadImg
    label="一级分类图"
    field="iconPath"
    updateImg={this.updateImg}
    rowInfo={detailInfo}
    imgSize={10000}
    formItemLayout={{
        labelCol: { span: 8 },
        wrapperCol: { span: 14 },
    }}
/>
  • 删除
// 批量删除
batchDeleteInfo = () => {
   let { selectedRowKeys } = this.state;
   let ids = selectedRowKeys.join(',');
   this.deleteInfo(ids);
}
// 删除公用方法
deleteInfo = (ids) => {
   confirm({
      title: '删除确认',
      content: '确定要删除所选数据吗?',
      okText: '确认',
      centered: true,
      cancelText: '取消',
      onOk: () => {
         this.props.dispatch({
            type: 'primary/deleteProClass', payload: { ids },
            callback: ({ code, data, message: info }) => {
               if (code === '0') {
                  message.success(info);
                  this.setState({
                     selectedRowKeys: []
                  })
                  this.getData();
               } else if (code === '-1') {
                  message.error(info);
               }
            }
         });
      },
      onCancel() {
      },
   });
}
  • 父子组件传值
{showModal && <ShowModal hideFildModel={this.showModal} getData={this.getData} rowInfo={rowInfo} />}

如何接受dva的props的返回数据

观察代码发现我们使用返回值要么用的是.then,要么用的callback回调函数,如何使用dva数据流处理页面数据或者做某些事

例如我们在子组件新增、编辑成功后,可以在父组件接受,子组件的成功行为做操作

// 去除子组件的callback获取返回值的方法
this.props.dispatch({
    type: 'primary/saveOneProClass',
    payload: param,
    // callback: ({ code, message: info }) => {
    //     if (code === '0') {
    //         this.props.getData();
    //         this.handleClose();
    //     } else {
    //         message.error(info);
    //     }
    // }
});

// 父组件通过result接收数据进行比较,做修改
componentWillReceiveProps(nextProps) {
   const { saveOneProClassResult } = nextProps.primary;
   if (saveOneProClassResult !== this.props.primary.saveOneProClassResult) {
      const { code, data } = saveOneProClassResult;
      if (code === '0') {
         this.getData();
         this.showModal('showModal', false);
      } else {
         message.error(saveOneProClassResult.message);
      }
   }
}

标签:axios,界面,第七课,dva,primary,dispatch,组件,return,payload
来源: https://www.cnblogs.com/Hsong/p/14057609.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有