Bootstrap

在umi+dva中使用useDispatch、useSelector替代dva中的connect


前言

最近实习的公司用到了umi框架开发,里面有一个umi+dva的使用,因此特地先看了dva的官方文档,回过头来看发现稍微有些差异,比如dva的connect被取消,采用useDispatch和useSelector来绑定state到view,本文记录一下model代码的注释以及各个参数的含义。本文主要参考了文章https://www.jianshu.com/p/1ded865efc22


一、View和Model的关系图解

dva是一个基于redux和redux-saga的数据流方案,原则上来说分为全局model和局部model,在很多中大型项目都建议采用这种方式,而不是简单的state+props。
在这里插入图片描述

二、model的使用

models文件夹定义了一些东西,其中namespace是全局的key,定义为一个字符串,state是初始值,他的优先级要小于在initialState。reducers接收action,更新state,用来处理同步操作,effects实现异步。

dva 通过 model 的概念把一个领域的模型管理起来,包含同步更新 state 的 reducers,处理异步逻辑的 effects,订阅数据源的 subscriptions 。

//model.js 基本结构
export const DemoModel = {
  nameSpace: 'demo', // 定义model名,如果没声明,会以文件作为namespace
  state:{}, // 初始state 优先级小于initialState
  reducers:{ 
    // reducer 是 Action 处理器,用来处理同步操作,等同于redux里面的reducer,接收action,同步更新state
    getList (state, { payload }) { // 第二个参数为 action = {type,payload} 
        //代码操作
      return payload 
    }
    },
  effects:{ 
    // Effect是一个 Generator 函数,内部使用 yield 关键字,标识每一步的操作
    *getRemote ({ payload },{put, call}) {  
      // 这里每个函数都有两个参数,(action,effect), effect = {put,call,select}
      // put 触发一个action,类似于dispatch
      // call 执行异步函数,比如请求 
      const data = yield call(getRemoteList)
      yield put({
        type: 'getList',
        payload: {"data":data} // 这里直接返回data会获取不到数据,因此我用对象又包了一层
      })
    },
    *delUser ({ payload:{ id } },{put,call}) {
      const data = yield call(delUserData, { id })
      yield put({
         type: 'getRemote', 
         payload: {}
       })
    },
  },
  subscriptions:{
    setup({ dispatch, history }) {
      return history.listen(({ pathname }) => { // {pathname} = location
        if (pathname === '/') {
          dispatch({
            type: 'getRemote', // 监听到进入主页,派发query事件
          })
        }
      });
    }
  }
}

三、connect的替代

import { useSelector, useDispatch,useStore } from 'umi';

const Index = () => {
  // useSelector 通过getState()方法找到demo的data
    const state = useSelector(state => state.getState().demo.data) 
  // useStore:如果store中的state改变,这个将不会自动更新
  //const state = useStore(state.getState())
  const dispatch = useDispatch()
  
  const deleteHandler = async (id) => {
    dispatch({
      type:'users/delUser',  
      payload:{
        id
      }
    })
  };
  
  return()
}
export default Index

原先connect的用法是这样的,代码如下:

import { connect } from 'umi';

const Index = (props) => {
  const { users, dispatch } = props
    const state = users.users.data
  const deleteHandler = async (id) => {
    dispatch({
      type:'users/delUser',  
      payload:{
        id
      }
    })
  };
  
  return()
}

const stateToProps = ({users}) => {
   return {
    users
  }
}
export default connect(stateToProps)(Index);
// 或者
export default connect(({users}) => ({
  users
}))(UserTable);

四、umi+dva的CURD应用

主要依靠三步走:service+model+component

// 1、service
export function remove(id) {
  return request(`/api/users/${id}`, {
    method: 'DELETE',
  });
}
// 2、model
*remove({ payload: id }, { call, put, select }) {
  yield call(usersService.remove, id);
  const page = yield select(state => state.users.page);
  yield put({ type: 'fetch', payload: { page } });
},
// 3、component
deleteHandler(){
  dispatch({
  	type: 'users/remove',
  	payload: id,
  });
}

以上内容参考https://github.com/sorrycc/blog/issues/62
自己的代码地址https://gitee.com/Kathysi/umi-dva–curd-application


总结

前端的技术更新得很快,因此需要不断学习!最后再次总结一下:

  • State:一个对象,保存整个应用状态
  • View:React 组件构成的视图层
  • Action:一个对象,描述事件
  • connect 方法:一个函数,绑定 State 到 View
  • dispatch 方法:一个函数,发送 Action 到 State
;