dva 從入門(mén)到入土

dva 是對(duì) redux 的一層淺封裝,基于 react 語(yǔ)言,實(shí)現(xiàn)前端代碼的分層

一般會(huì)分為3層:

  • component:組件渲染、展示頁(yè)面
  • models:數(shù)據(jù)組裝、處理
  • services:接口調(diào)用、拿數(shù)據(jù)

以 smart-ui 項(xiàng)目中用戶列表模塊為例:


smart-ui

1. router.js 文件中配置路由,指定具體路徑所要加載的 views 和 models

{
    path: '/security/users',
    models: () => [import('./models/security/user')],
    component: () => import('./views/security/user/'),
}

2. services

.roadhogrc.js文件中配置好代理請(qǐng)求地址

proxy: {
    "/api/v1/weather": {
      "target": "https://api.seniverse.com/",
      "changeOrigin": true,
      "pathRewrite": { "^/api/v1/weather" : "/v3/weather" }
    },
    "/services": {
        "target": "http://ip地址:8080/",
        "changeOrigin": true,
        "pathRewrite": { "^/services" : "/services" }
      },
  },

serviecs/user.js中定義好接口,獲取原始數(shù)據(jù)。項(xiàng)目中,已對(duì)常用的增刪改查做了一層封裝(包括分頁(yè)).
對(duì)于自定義方法,提供 url、method、data(可選),返回 request 封裝好的 http 請(qǐng)求

export async function query({page = 1 , pageSize = 10 , ...qs}) {
    return user.listPage(page,pageSize,qs)
}

export async function get({id}) {
    return user.get(id)
}

export async function create (params) {
    return user.create(params);
}

export async function update (params) {
    return user.update(params);
}

// 用戶設(shè)置 自定義方法
//修改用戶
export async function modify(payload) {
    return request({
        url: `${apiPrefix}/security/user/modify`,
        method: 'put',
        data: payload
    })
}

3. models

import pathToRegexp from 'path-to-regexp'
import modelExtend from 'dva-model-extend'
import * as user from 'services/security/user'
import { pageModel } from 'models/common'
import { message } from 'antd'

export default modelExtend(pageModel, {

  namespace: 'secUser',

  state: {
   currentItem: {},
   modalVisible: false,
   modalType: 'create',
   selectedRowKeys: [],
  },
  
  // 添加一個(gè)監(jiān)聽(tīng)器,當(dāng)pathname === '/security/users'時(shí)執(zhí)行dispatch
  subscriptions: {
    setup ({ dispatch, history }) {
      history.listen((location) => {
        if (location.pathname === '/security/users') {
          dispatch({ 
              type: 'query', 
              payload: location.query || {},
          })
        }
      })
    },
  },

// 
  effects: {
    * query ({
      payload,
    }, { call, put }) {
      const result = yield call(user.query, payload)
      const { success, message, status, data } = result
      if (success) {
        yield put({
          type: 'querySuccess',
          payload: data,
        })
      } else {
        throw result
      }
    },

    * create ({ payload }, { call, put,select }) {
      const {data} = yield call(user.create, payload)
      message.info("新增成功");   
      yield put({ type: 'hideModal' })
      const { pagination: { pageSize,current } } = yield select(_ => _.secUser)
      yield put({ type: 'query', payload: {pageSize, page:current } })
    },

    * update ({ payload }, { select, call, put }) {
      const id = yield select(({ secUser }) => secUser.currentItem.id)
      const newUser = { ...payload, id }
      const {data} = yield call(user.update, newUser)
      message.info("修改成功");
      yield put({ type: 'hideModal' })
      const { pagination: { pageSize,current } } = yield select(_ => _.secUser)
      yield put({ type: 'query', payload: {pageSize, page:current } })
    },
  },

  reducers: {
     showModal (state, { payload }) {
      return { ...state, ...payload, modalVisible: true }
    },

    hideModal (state) {
      return { ...state, modalVisible: false }
    },
  },
})
  • query、update 前面的 * 號(hào),表示這個(gè)方法是一個(gè) Generator函數(shù)
  • subscriptions:用于添加一個(gè)監(jiān)聽(tīng)器
  • effects:異步執(zhí)行 dispatch,用于發(fā)起異步請(qǐng)求
    • call 是調(diào)用執(zhí)行一個(gè)函數(shù) (調(diào)用service里面的方法)
    • put 則是相當(dāng)于 dispatch 執(zhí)行一個(gè) action
    • select 則可以用來(lái)訪問(wèn)其它 model
  • reducers:同步請(qǐng)求,主要用來(lái)改變state

4.component

注意:組件入口文件一定要命名為 index.js ,否則會(huì)找不到

import React from 'react'
import PropTypes from 'prop-types'
import { routerRedux } from 'dva/router'
import { connect } from 'dva'
import { Row, Col, Button, Popconfirm } from 'antd'
import List from './List'
import Filter from './Filter'
import Modal from './Modal'
import { Page } from 'components'
import { i18n }  from 'utils'

const User = ({ location, dispatch, secUser, loading }) => {
  const { dataSource, pagination, currentItem, modalVisible, modalType, selectedRowKeys } = secUser
  const { pageSize } = 10

  const modalProps = {
    item: modalType === 'create' ? {} : currentItem,
    visible: modalVisible,
    maskClosable: false,
    confirmLoading: loading.effects['secUser/update'],
    title: modalType === 'create' ? i18n('lab.user.create') : i18n('lab.user.update'),
    wrapClassName: 'vertical-center-modal',
    onOk (data) {
      dispatch({
        type: `secUser/${modalType}`,
        payload: data,
      })
    },
    onCancel () {
      dispatch({
        type: 'secUser/hideModal',
      })
    },
  }

  const listProps = {
    dataSource,
    loading: loading.effects['secUser/query'],
    pagination,
    location,
    onChange (page) {
      const { query, pathname } = location
      dispatch(routerRedux.push({
        pathname,
        query: {
          ...query,
          page: page.current,
          pageSize: page.pageSize,
        },
      }))
    },
    onDeleteItem (id) {
      dispatch({
        type: 'secUser/delete',
        payload: id,
      })
    },
    onEditItem (item) {
      dispatch({
        type: 'secUser/showModal',
        payload: {
          modalType: 'update',
          currentItem: item,
        },
      })
    },
    rowSelection: {
      selectedRowKeys,
      onChange: (keys) => {
        dispatch({
          type: 'secUser/updateState',
          payload: {
            selectedRowKeys: keys,
          },
        })
      },
    },
  }

  const filterProps = {
    ...
  }

  const handleDeleteItems = () => {
    dispatch({
      type: 'secUser/multiDelete',
      payload: {
        ids: selectedRowKeys,
      },
    })
  }

  return (
    <Page inner>
      <Filter {...filterProps} />
      <List {...listProps} />
      {modalVisible && <Modal {...modalProps} />}
    </Page>
  )
}

User.propTypes = {
  secUser: PropTypes.object,
  location: PropTypes.object,
  dispatch: PropTypes.func,
  loading: PropTypes.object,
}

export default connect(({ secUser }) => ({ secUser}))(User)
  • connect方法將組件與數(shù)據(jù)關(guān)聯(lián)在一起
    export default connect(({ secUser }) => ({ secUser}))(User)
  • secUser 必須與對(duì)應(yīng) models 里面定義的 namespace 字段一致
  • 組件中發(fā)起請(qǐng)求調(diào)用 dispatch
    • type 字段對(duì)應(yīng) models 中 effects 和 reducers 對(duì)應(yīng)方法
    • payload 為傳參對(duì)象
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容