全栈手册首页投稿(暂停使用,暂停投稿)程序员

我是这样灵活控制redux的state树的

2016-12-10  本文已影响691人  JasonFF

Redux的操作中,做一个action往往比较麻烦,要写很多个文件。个人觉得很浪费时间,因为大部分内容只是一些机械的复制粘贴操作。

所以我做了一个通用的action来非常快速和灵活的发action来改变redux的state树。

说明一下,整个操作的前提是已经进行了 redux-immutable 改造。否则很难对内层的state数据进行精确操作。

废话不多说了,上代码。

里面已经包含了向后台请求数据的操作。

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({})
        }
}


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:'写字楼'
        }]
    }
})

Paste_Image.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没有它们自己的设置。因为他们是被生成出来的。而不是刚开始就定义好的。
四、其他。。。

如果有什么建议,马上留言哦。谢谢您的关注。

上一篇下一篇

猜你喜欢

热点阅读