umi+dva model的数据管理教程

阅读本文章需有以下基础

1.react
2.dva
3.umi
本文主要是使用umi+dva完成仓库管理,model文件的结构、写法,connect怎么把model的数据和组件关联,数据之间如何传递修改等问题。
(本人也在学习中,以下内容经供参考,可能存在一些问题,欢迎指正)

一、dva是基于redux、redux-saga和react-router的轻量级前端框架

我简单的理解为redux用于处理仓库的同步数据,redux-sage用于处理仓库的异步数据,react-router用于页面跳转。dva官网https://dvajs.com/guide/
在这里插入图片描述
在这里插入图片描述

二、umi干嘛用的

帮我们省去很多麻烦事的框架。官网https://umijs.org/zh-CN/docs
在这里插入图片描述

**三、 目录的组织结构

在这里插入图片描述
在umi搭建的项目中的 约定式的 model 组织方式如上,所以先创建一个umi项目(不会的可以看官网),然后在pages文件下创建以下几个文件(一般项目上都会有这几个文件,这里的组件表示的是子组件,这里所说页面其实也是一个组件)
在这里插入图片描述

四、model里有些啥?

model.js文件里的内容如下,model里其实就是一个对象,我们把这个对象导出

export default {
  //namespace命名空间,相当于给model取个名字,但是各个model的namespce是不能重复的
  namespace: 'test',
  //state我理解为是数据仓库,就是存数据的地方,model里的数据都是存放在这里的
  state : {
    name: 'wang'
  },
  /*reducers把数据存到仓库(存到state)里的唯一方法,我们修改state里的数据不能直接像this.name='liu'这样去修改,而必须通过调用reducers里的方法,在之后会详细讲到*/
  reducers:{

  },
  /*异步方法,简单来说我们的异步请求就写在这里*/
  effects: {

  },
  /*订阅,在这里我的理解就是监听页面的,比如监听到进入了某某页面就让它执行相关代码之类的*/
  subscriptions: {

  }
}

model的结构就是这个样子,但是怎么把model和我们写的组件关联起来呢,只需要用到connect就可以啦。首先从dva中导入connect,然后把Index包裹起来。

index.js文件里的内容如下

import React from 'react';
import { connect } from 'dva'

class Index extends React.Component {
  render() {
    return (
      <div>
        <div className='box'>
        </div>
      </div>
    );
  }
}

//通过connect把model和我们写的Index关联起来,之后会解释mapStateToProps,先这样写,test是model的命名空间
const mapStateToProps = ({test}) => {
  return {
    ...test
  }
}
export default connect(mapStateToProps)(Index);

简单解释一下这个connect,connect是一个高阶函数,高阶函数就是说把一个函数作为另一个函数的参数。connect接受函数mapStateToProps作为参数,connect(mapStateToProps)返回的也是一个函数,然后再把Index作为这个返回的函数的参数。

五、如何进行数据传递的?

先看一张图
在这里插入图片描述
简单理解一下就是我们的页面或者订阅通过dispatch去调用reducer和effect里的函数,在effect里面去实现services请求,把数据通过reducer放到state里面(reducer操作state里的数据的唯一途径),最后再通过connect吧state和页面关联起来,我们就可以在页面中拿到model里的数据。在页面中调用接口dispatch-》effect里面的方法,在页面中修改state的里的数据dispatch-》reducer里面的方法。
**

六、connect详解

之前说到connect把model和页面链接起来,为了方便讲解,现在model.js reducers里面先写一个save方法。

  reducers:{
    save(state,action){
      //必须return,否则会报错
      return {
        name: '111'
      }
    }
  },

回到Index.js页面,我们再来说connect。

connect(mapStateToProps, mapDispatchToProps,mergeProps,options)

connect接收四个参数
mapStateToProps允许我们将 store 中的数据作为 props 绑定到组件上。
mapDispatchToProps将action作为props绑定到组件上。
mergeProps和options基本不传,我们只要掌握前两个就好了

mapStateToProps(state,ownProps){ retunrn obj } 必须返回一个对象

不妨打印一下看看两个参数是什么东西,以及返回的对象会到哪里去
Index.js内容如下

import React from 'react';
import { connect } from 'dva'

class Index extends React.Component {
  componentDidMount() {
    console.log('=========props');
    console.log(this.props);
  }

  render() {
    return (
      <div>
        <div>
          <div>姓名:{this.props.name}</div>
        </div>
      </div>
    );
  }
}
const mapStateToProps = (state, ownProps) => {
  console.log('mapStateToProps=========');
  console.log('state',state);
  console.log('ownProps',ownProps);
  return {
  		hobby: '打游戏'
  }
}
export default connect(mapStateToProps)(Index);

在这里插入图片描述
这就很明显了,我们在mapStateToProps 里返回什么,组件的props就会接收到什么,然而第一个参数里我们可以取到model里state的值,所以我们只需要把state里的值返回,这样我们就可以在组件中得到model的值。

const mapStateToProps = ({test}) => {
  return {...test}
}

mapDispatchToProps可以是一个对象也可以是一个函数
mapDispatchToProps(dispatch,ownProps),ownProps与上面的一样就不多加赘述

注意:对象的属性值需是函数

//对象写法
// const mapDispatchToProps = {
//   add: () => ({type: 'test/save'}),
// }

//函数写法
const mapDispatchToProps = (dispatch) => ({
  save() {
    dispatch({type: 'test/save'})
  },
})
export default connect(mapStateToProps,mapDispatchToProps)(Index);

返回的函数也会被props接收,这样我们就可以在props里取到该函数并调用它。
注意:如果传了第二个参数mapDispatchToProps,那么props里就没有dispatch了,也就是说不能通过this.props.dispatch({type: ‘test/save’)这样去派发它,只能通过调用mapDispatchToProps返回的函数this.props.save()进行派发。

**
七、Reducer

//格式如下
reducers:{
      save(state,action){
      //必须return,否则会报错
      return {
        name: '111'
      }
    }
  },

页面组件与model关联以后我们是这样去使用它的。

   this.props.dispatch({type: 'test/save',payload: {msg: '你好呀'}})

在这里插入图片描述
‘上次的state’做个解释,就是说如果我连续dispatch了两次reducer,第二次的参数state就是第一次的dispatch之后返回的state,也就是说第一次reducer以后state的值变了,第二次拿到的state就是改变后的state.
我们一般把需要传递的数据都放在payload里面,type的值一般是用不到的,所以一般我们会这样写。

reducers:{
    save(state,{payload}){
      return {...state, ...payload}
    }
  },

八、subscriptions

  subscriptions: {
    test({history,dispatch}){
      console.log('history',history);
      console.log('dispatch',dispatch);
    }
  }

在subscriptions里随便写一个方法,打印出来看看。by the way,subscriptions里的方法,随便进入一个页面则都会执行,不需要与model进行关联才会调用,比如我现在是写这个目录下的,我随便进入一个其他的页面依旧打印。
在这里插入图片描述
在这里插入图片描述
有人可能觉得,那事件监听就事件监听被,干嘛要单独抽出来放在model里面弄成个订阅。如果你需要用到一些数据,并且处理数据后的逻辑仅与当前model相关,那么就应该用 subscriptions。这么一想是不是,我们就可以在subscription里方便的操作model里面的数据了呀。

  subscriptions: {
    test({history,dispatch}){
      history.listen((location) => {
        if(location.pathname === '/reactRouter/路由起步/user'){
          dispatch({type: 'save',payload:{age: '18'}}) //在model里面dispatch就不需要加命名空间哦
        }
      })
    }
  }

九、effects

格式为*func(action,effects),action和之前的一样,effects里有很多方法,只要会用call和put就够了。

我们在effects里调用接口,我这里只做个模拟,在service.js里模拟一个接口,导出它,因为请求接口是异步的所以在这里使用async
在这里插入图片描述

在这里插入图片描述
好了,现在我们就可以在componentdidmount里面进行派发调用这个接口,然后把接口返回的数据存到state里,再把state里的数据显示到页面上啦。
在这里插入图片描述
页面显示
在这里插入图片描述

  • 19
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值