DvaJS的model属性

namespace

namespace为model 的命名空间,同时也是他在全局 state 上的属性,只能用字符串,不支持通过 . 的方式创建多层命名空间

// model/test.js
const TestModel = {
	namespace: "test"
};
export default TestModel

// pages/test/test.js
import { connect } from 'dva';

export default
@connect()
class Test extends React.Component {
  componentDidMount() {
  	const { dispatch } = this.props
    dispatch({
      type: 'test/**'
    }
    /**
     * 这里的type: 'test/**'  test就是我们在namespace中设置的model命名
     * test/**   "/"后为effects中的方法
     */
  }
}

state

state属性 model中用于数据存储

// model/test.js
const TestModel = {
	namespace: "test",
  state: {
  	data: [1, 2, 3],
    str: 'model-state'
  }
};
export default TestModel

// pages/test/test.js
import { connect } from 'dva';
/**
 * connect(({ test }) => ({}))
 * 通过connect建立namespace名为test的model与当前组件的链接
 * 并读取model中的state与当前组件的props进行绑定
 */
export default
@connect(({ test }) => ({
  data: test.data,
  str: test.str
}))
class Test extends React.Component {
  componentDidMount() {
  	const { data, str } = this.props
    console.log(data, str) // [1, 2, 3] 'model-state'
  }
}

effects

effects用于处理异步操作和业务逻辑,不能直接修改state,由action触发,可以触发action,可以和服务器进行交互,可以获取全局state的数据
effects 有三种属性 put, call, select

put

put 用于触发action

// model/test.js
const TestModel = {
	namespace: "test",
  state: {
  	data: [1, 2, 3]
  },
  effects: {
  	* fetch({ payload }, { put }) {
    	yield put({
      	type: 'setData'
      })
      // [1, 2, 3]
    },
    * update({ payload }, { put }) {
    	yield put({
      	type: 'fetch'
      })
      // [1, 2, 3]
    }
    /**
     * yield put() 触发action 可以调用reducers和effects中的方法
     */
  },
  reducers: {
    setData(state, { payload }) {
      console.log(payload)
      return {
      	...state,
        data: payload
      }
    }
  }
};
export default TestModel

call

call 用于调用异步逻辑,支持promise

// model/test.js
import { queryList } from '@/services/test';
const TestModel = {
	namespace: "test",
  state: {},
  effects: {
  	* fetch({ payload }, { call }) {
    	const data = yield call(queryList, payload)
      console.log(data) // data为queryList请求的返回结果
      /**
       * yield call() 
       * 第一个参数为异步操作请求函数
       * 第二个参数为函数所传递的值
       */
    }
  }
};
export default TestModel

select

select 用于从state获取数据

// model/test.js
const TestModel = {
	namespace: "test",
  state: {
    data: [1, 2, 3]
  },
  effects: {
  	* fetch({ payload }, { select }) {
    	const data = yield select(state => state.test.data)
      console.log(data) // [1, 2, 3]
    }
    /**
     * 通过select 获取state中的数据, test为namespace名
     */
  }
};
export default TestModel

put与put.resolve

yield put直接调用reducers,堵塞 => 同步
yield put调用非reducers,非堵塞 => 异步
yield put.resolve调用,堵塞 => 同步

export default const TestModel = {
	effects: {
		* asyncInitData({ payload }, { put }) {
       yield put({
         type: 'initData',
         payload: payload
       })
		},
    // 使用yield put 调用reducers
    * reducersBtn(_, { put }) {
    	console.log('1')
      yield put({
      	type: "initData",
        payload: '2'
      })
      console.log('3')
      // 打印结果为 1, 2, 3
    },
    // 使用yield put 调用effects
    * button(_, { put }) {
    	console.log('1')
      yield put({ 
        type: 'asyncInitData',
        payload: '2'
      })
      console.log('3')
      // 打印结果为 1, 3, 2
    },
     // 使用yield put.resolve 调用effects
    * resolveBtn(_, { put }) {
      console.log('1')
      yield put.resolve({ 
        type: 'asyncInitData',
        payload: '2'
      })
      console.log('3')
      // 打印结果为 1, 2, 3
    }
	},
  reducers: {
  	initData(state, { payload }) {
    	console.log(payload)
      return {
      	...state,
        ...payload
      }
    }
  }
}

callback和Promise

在effects中定义用于处理异步操作和业务逻辑的方法,我们可以通过callback或者promise获取一个返回值
(state的值无法即使更新时可以使用)

callback

// model.js
export default const TestModel = {
  namespace: 'test',
	effects: {
		* query({ payload, callback }, { call }) {
      const response = yield call(query, payload)
      if (callback) callback(response)
		}
	}
}
// test.jsx
import React, { useEffect } from 'react';

const Test = (props) => {
	useEffect(() => {
  	dispatch({
      type: 'test/query',
      callback: (res) => {
        console.log(res)
      }
    }).then(res => {
      console.log('queryCbd-res: ', res)
    })
  })
}

**

Promise

effects中的方法会return 返回一个Promise对象

// model.jsexport default {  namespace: 'test',	effects: {		* query({ payload }, { call }) {       const response = yield call(query, payload)       return new Promise(function(resolve, reject){         if (response.code == 200) {           resolve(response.data)         }         reject(response)       })      // 或者写成return response effects会return一个proimse对象      //return response		}	},}
// test.jsximport React, { useEffect } from 'react';const Test = (props) => {	useEffect(() => {  	dispatch({      type: 'test/query'    }).then(res => {      console.log('test/query: ', res)    })  })}

reducers

reducers 用于处理同步操作,唯一可以修改state的地方,有action触发

// model/test.jsconst TestModel = {	namespace: "test",  state: {    data: [1, 2, 3]  },  effects: {  	* fetch(_, { put, select }) {      const data = yield select(state => state.test.data)    	yield put({      	type: 'setData',        payload: data      })      const newData = yield select(state => state.test.data)      console.log(newData) // [2, 4, 6]    }  },  reducers: {    // 在reducers中进行一些数据的修改, 并返回更新state中的数据    setData(state, { payload }) {      return {      	...state,        data: payload.map(item => item * 2)      }    },    /**    setData(state, action) {      const { payload  } = action      return {      	...state,        data: payload.map(item => item * 2)      }    }    */  }};export default TestModel

同时我们在页面也可以通过dispatch对触发reducers去修改state中得数据源

import React, { useEffect } from 'react';const Test = (props) => {	useEffect(() => {  	dispatch({      type: 'test/setData',      payload: [2, 4, 6]    })  })}

subscriptions

subscription 是订阅,用于订阅一个数据源,根据需要dispath相应的action,在app.start()时被执行
数据源可以是当前的时间,服务器的websocket链接,keyboard输入(鼠标,键盘),geolocation变化,history路由变化等

// model/test.jsimport key from 'keymaster'; // Keymaster是一个简单的微型库,用于在Web应用程序中定义和分发键盘快捷键const TestModel = {	namespace: "test",  state: {},  effects: {},  reducers: {},  subscriptions: {    /**     * 这里的setup方法可以随便命名,     * 当监听有变化时就会依次执行     * dispatch和history 如文档中一样     * dispatch 可以调用effects与reducers中的方法     * history 获取当前路由的信息     */    setup({ dispatch, history }) {      // 监听当前浏览器的页面大小变化, 页面发生改变时就会触发dispatch方法      window.onresize = (e) => {        // dispatch({ type: 'effects'})        console.log(e)      }    },    keyboard({ dispatch }) {      // 监听当鼠标在页面中点击时触发      document.addEventListener('click',() => {        console.log('鼠标点击时触发')      })    },    keyEvent({ dispatch }) {      // 监听ctrl + up键点击时触发      key('ctrl+up', () => {      	console.log('ctrl+up')      })    },    watchHistory({ dispatch, history }){      // 获取当前页面的所有路由信息      history.listen((location) => {        console.log(location)      })    }  }};export default TestModel

connect 与 @connect

connect 的作用是将组件和models结合在一起,将models中的state数据绑定到组件的props中,并提供一些额外的功能,如dispatch

connect 方法返回的也是一个react组件
connect 方法传入的第一个参数是 mapStateToProps 函数,该函数需要返回一个对象,用于建立 State 到 Props 的映射关系
connect 接收一个函数,返回一个函数

connect()()

export default connect(({ user, login, global = {} }) => ({  userInfo: user.userInfo,  login: login.userLogin,  notices: global.notices}))(BasicLayout);// BasicLayout 为组件 class BasicLayout extends React.Component {}

@connect

@connect 为ES7中的语法( @Decorator 装饰器 )
@方法名 可以对一些对象进行装饰包装然后返回一个被包装过的对象,可以装饰的对象包括:类,属性,方法等

export default@connect(({ user, login, global = {} }) => ({  userInfo: user.userInfo,  login: login.userLogin,  notices: global.notices}))class BasicLayout extends React.Component {}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

竹苏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值