React中全局状态管理官方推荐使用Redux,Redux的使用场景其实在单个应用中是处于使用率只有20%,却有80%的学习成本。可是说是React全家桶中最难理解的部分了,相信很多人学习它时,各个概念整很迷糊。我就是要放弃Redux的时候,了解React-redux和redux-saga, 它们是对redux的简化处理工具。可他们配置和文件结构,依然麻烦。直到Dva(低洼)的出现将React全局状态管理简化到了极致。那么今天带大家一起快速学习下Dav中全局状态的使用技巧,本篇文章仅仅是对使用方式的个人理解。
由于时间关系,测试内容可能有误,请看官主要理解总结中的内容。
本次演示环境使用UmiJs搭建,因为Dva已经很久不维护了,并且已经交由Umi管理,所以使用Umi来创建React项目是目前最方便的。参考官网环境搭建好后:如下
默认src/models下创建的所有符合model规范的文件都会自动注册到umijs中。创建src/models/users.js,
import {apiUserList} from '@service/user.js'
export default {
namespace: 'users',
state: {
name: ''
},
effects: {
*fetchUserName({ payload }, { call, put }) {
const userName = yield call(apiUserList, payload)
yield put({ type: 'setName', payload: userName })
},
},
reducers: {
setName(state, { payload }) {
return {
...state,
name: payload
};
},
},
};
创建src/pages/user.jsx
import React from 'react';
import { connect } from 'dva';
const users = ({ dispatch, userName }) => {
const setUserName = () => {
dispatch({
type: 'users/setName',
payload: '我小桃',
});
};
return (
<>
用户页面{userName}
>
);
};
const mapStateToProps = (state) => {
console.log(state);
return {
userName: state.users.name,
};
};
export default connect(mapStateToProps)(users);
运行yarn start
【命名空间】是外部分发(dispatch)调用model时,actions里type属性的前缀,后面跟reducers或effect的方法名。使用示例如下。model内部调用方法使用时可是省略前缀。
dispatch({
type: 'users/setName',
payload: '我小桃',
})
存储全局变量的仓库,核心使用的就是state,却是最简单理解的。结构对象和数组都可。
方法签名(state是状态,payload是分发时传的参数)
setName(state, { payload }) {}
唯一操作state的地方(CURD),即可对内(effects使用)也可对外。外部想要写state可以直接dispatch到reducers的方法来进行操作state。由于外部组件通过connect后可以获取(读)state的值,所以写操作必须使用dispatch。当然如果外部组件涉及到异步操作,比如删除用户是异步的话,这种情况往往实践都是直接dispatch到effects方法。而effects方法要处理需要分两步走:(1)调用异步接口删除用户数据(2)model内部dispatch到reducers的方法,让reducers删除state数据。
使用示例
*fetchUserName({ payload }, { call, put }) {
const userName = yield call(apiUserList, payload)
yield put({ type: 'setName', payload: userName })
},
最佳实践,一般是做异步业务CRUD,调用接口后再调用reducers中的方法来重新设置state。往往是方便外部组件使用,外部只调用effects方法就完成2部操作操作接口和操作state。其实也可以外部组件自己调用异步接口,之后再dispatch到reducers,这样就能省下一个effects,看个人喜好推荐使用effects。
方法签名(①payload是外部dispatch时传的参数;②call是可以调用接口的方法,call调用接口时第一个参数是调用接口的方法名称,第二个参数是调用接口的参数;③put是effects特有的方法,类似外部调用的dispatch。dispatch和put参数数都是Action对象(Action对象包含type属性和payload属性)
1. 引入dva连接器
import { connect } from 'dva';
2. 使用连接器连接组件
export default connect(mapStateToProps)(组件名称);
3. 定义一个model中的state转为组件props的方法(方法返回值会赋值给props);
const mapStateToProps = (state) => {
console.log(state);
return {
userName: state.users.name,
};
};
4. 组件props自带dispatch方法和第三步转化后的属性
组件内部如果使用state,可以直接通过转化方法间接使用state。
const 组件 = ({ dispatch, userName }) => {
}
(1)如果需要异步修改数据库和state则可以dispatch到effects方法
(2)如果仅仅修改state不做接口调用,则dispatch到reducers方法即可。
dispatch({
type: '[namespace]/effects或reducers的方法名称',
payload: '我小桃',
});
(完~)