我是这样灵活控制redux的state树的
2016-12-10 本文已影响691人
JasonFF
在
Redux
的操作中,做一个action往往比较麻烦,要写很多个文件。个人觉得很浪费时间,因为大部分内容只是一些机械的复制粘贴操作。
所以我做了一个通用的action来非常快速和灵活的发action来改变redux的state树。
说明一下,整个操作的前提是已经进行了 redux-immutable 改造。否则很难对内层的state数据进行精确操作。
废话不多说了,上代码。
- action.js
里面已经包含了向后台请求数据的操作。
import fetch from 'isomorphic-fetch';
import {
truck
} from 'actions';
const BASE_URL = "https://api.jasonff.top/";
export const action = ({
moduleName,
body,
url,
config,
method,
goods,
unload,
callback,
query,
deepMerge
}) => (dispatch) => {
const resData = (json) => {
const data = {
[`${moduleName}`]: {
loaded: true,
...json,
...goods
}
}
truck({data:data,name:`${moduleName}`,deepMerge:deepMerge})(dispatch)
if (callback) { // callback的存在,可以在实际使用中没必要在componentWillReceiveProps中做回调操作。可以直接对某个action做异步回调。精确,快速。
callback(json)
}
}
if (unload) { // unload的目的是在state树中完全卸载这条数据。
return truck({data:null,name:`${moduleName}`,unload:true})(dispatch)
}
if (method && url) { // 发送异步请求的操作。
let cfg = config || {};
let _url = url;
if (query) { // 支持query操作,没有必要进行url字符串拼接了。
let keys;
_url = url + '?';
try {
keys = Object.keys(query)
} catch (e) {
console.log(e)
}
for (var i = 0; i < keys.length; i++) {
_url = _url + `${keys[i]}=${query[keys[i]]}&`
}
_url = _url.replace(/\&$/,'')
}
cfg.headers = Object.assign({}, cfg.headers, {
'Content-Type': 'application/json'
})
fetch(BASE_URL+_url,Object.assign({},cfg,{
method: method,
body: JSON.stringify(body)
})).then(res => res.json()).then(json => resData(json)).catch(ex => resData(ex))
} else {
resData({})
}
}
- truck.js
const TRUCK_LOAD = 'TRUCK_LOAD';
const TRUCK_UNLOAD = 'TRUCK_UNLOAD';
const initialState = Immutable.Map()
const truck_load = (data,name,deepMerge) => ({
type: TRUCK_LOAD,
data: data,
name: name,
deepMerge: deepMerge
})
const truck_unload = (data,name) => ({
type: TRUCK_UNLOAD,
name: name
})
export default (state = initialState, action) => {
switch (action.type) {
case 'TRUCK_LOAD':
// 下面是主要的代码来merge发上来的各个action
if (action.deepMerge) { // 如果是需要deepMerge的就deepMerge,这个功能可以改变state树中的深层的数据。
let an = Immutable.fromJS(action.data);
let re = state.mergeDeep(an);
return re;
}
// 下面的代码只merge到第二层,可以进行第二层数据上面的覆盖和替换。
let sn = state.get(action.name)||Immutable.Map();
let an = Immutable.fromJS(action.data[action.name]);
let nv = sn.merge(an);
let newAction = Immutable.Map().set(action.name, nv);
let re = state.merge(newAction);
return re;
case 'TRUCK_UNLOAD':
// 卸载掉了这条数据
state.delete(action.name)
return state
default:
return state;
}
}
export const truck = ({data,name,unload,deepMerge}) => {
if (unload) {
return (dispatch)=>{
dispatch(truck_unload(null,name))
}
}
return (dispatch)=>{
dispatch(truck_load(data,name,deepMerge))
}
}
下面是我的使用示例
- 没有异步请求的情况
this.props.action({
moduleName: `Breadcrumb`,
goods: {
data: [{
url:'/'+selectedCity.domain,name:'首页'
},{
url:`/${selectedCity.domain}/buildings`,name:'写字楼'
}]
}
})
![](https://img.haomeiwen.com/i2033728/0eb1301971ac6240.png)
- 有异步请求数据的情况
import React from 'react';
import {Message} from 'components';
const style = require('./Collect.scss');
export default ({action,status,type,id,checkLogin}) => {
let _status = status;
const ts = {
b: {
name: '收藏楼盘',
falseurl: 'collections/buildings?buildingId='+id,
trueurl: 'collections/buildings?buildingId='+id,
param: function(_s){
return {
moduleName: 'BuildingDetail',
goods: {
data: {
collection: !_s
}
},
deepMerge:true
}
}
},
r: {
name: '收藏房源',
falseurl: 'collections/rooms?rooomId='+id,
trueurl: 'collections/rooms?rooomId='+id,
},
i: {
name: '收藏众创空间',
falseurl: 'incubator/collect?incubatorId='+id,
trueurl: 'incubator/delete_collect?id='+id,
param: function(_s){
return {
moduleName: 'IncubatorDetail',
goods: {
data: {
collection: !_s
}
},
deepMerge:true
}
}
}
}
const onClick = () => {
checkLogin()
.then(res=>action({
moduleName: "Collection",
method: `${_status?'DELETE':'POST'}`,
url: ts[type][_status+'url'],
needToken: true,
callback: function(data) {
if (data.status == 1) {
try {
const eR = document.getElementById("collect_e");
eR.style.opacity = `${_status?1:0}`;
} catch (e) {
console.log(e)
}
try {
const fR = document.getElementById("collect_f");
fR.style.opacity = `${_status?0:1}`;
} catch (e) {
console.log(e)
}
Message('success',_status?'取消收藏成功!':'收藏成功!')
action(ts[type]["param"](_status))
}
}
})
)
}
return <span onClick={onClick} className={style.container}>
<i id="collect_e" style={{opacity:`${status?0:1}`}} className="soubanicon"></i>
<i id="collect_f" style={{opacity:`${status?1:0}`}} className="soubanicon"></i>
<span className={style.title}>{_status?"已收藏":ts[type].name}</span>
</span>
}
最后分析一下我的这个方法吧
好处就不说了,就是非常快速灵活的发送action,想改什么就改什么。
坏处:
一、 难以设置reducer的默认值。数据结构因为太灵活不固定所以难以预测。
二、不能对于action进行很系统的管理,只有发了之后action才看到它存在,不能在刚开始的时候就知道所有的action。其实跟第一点一样。
三、每个action没有它们自己的设置。因为他们是被生成出来的。而不是刚开始就定义好的。
四、其他。。。
如果有什么建议,马上留言哦。谢谢您的关注。