Incubator-104-frontend / sherlock

0 stars 0 forks source link

Action 撰寫方式不一致 #1

Open DerekHung opened 7 years ago

DerekHung commented 7 years ago

以下表列幾種code中的action 寫法 action 撰寫的方式不一致之外,有些寫法會造成大量的side effect 再來相似的action 在get / post 的時候沒有固定的流程跟驗證

export const GETACCUSEITEM = 'GETACCUSEITEM';
export function getAccuseItem( params ) {
    return (dispatch, getState) => {
        const state = getState();
        const accuseType = params.type;
        const checkKey = accuseType === 1 ? 'activity' : 'user';
        const itemData = state.accuse.accuseItem[checkKey];
        const check = itemData.length > 0;

        if(check){
            return dispatch({
                type: GETACCUSEITEM,
                accuseType: checkKey,
                itemData
            });
        }else{
            params.productKey = clientConfig.params.apnum;

            return $.get('/ajax/accuse/getAccuseItem', params, response =>{
                dispatch({
                    type: GETACCUSEITEM,
                    accuseType: checkKey,
                    itemData,
                    response
                });
            });
        }
    };
}
export const ACCUSE_TERRIBLE_PERSON = 'ACCUSE_TERRIBLE_PERSON';
export function accuseTerriblePerson( selection, comment ) {
    return (dispatch, getState) => {
        var params = {
            //pid: this.props.user.pid,
            targetPid: getState().accuse.accuseData.pid,
            accuseItem: selection,
            description: comment,
            otherComment: '',
            ip: "",
            language: "",
            browser: "",
            https: "",
            cookie: ""
        };

        return dispatch({
            'CALL_API': {
                type: ACCUSE_TERRIBLE_PERSON,
                method: 'post',
                target: '/accuse/accuseTerriblePerson',
                params: params
            }
        });
    };
}
export const ACCUSE_TERRIBLE_ACTIVITY = 'ACCUSE_TERRIBLE_ACTIVITY';
export function accuseTerribleActivity( selection, comment ) {
    return (dispatch, getState) => {
        var params = {
            //productKey: clientConfig.params.apnum,
            //pid: getState().user.pid,
            targetPid: getState().accuse.accuseData.userInfo.pid,
            aid: (getState().accuse.accuseData.aidParent !== null)? getState().accuse.accuseData.aidParent : getState().accuse.accuseData.aid,
            commentId: (getState().accuse.accuseData.aidParent !== null)? getState().accuse.accuseData.aid : "",
            accuseItem: selection,
            description: comment,
            otherComment: "",
            ip: "",
            language: "",
            browser: "",
            https: "",
            cookie: ""
        };

        return dispatch({
            'CALL_API': {
                type: ACCUSE_TERRIBLE_ACTIVITY,
                method: 'post',
                target: '/accuse/accuseTerribleActivity',
                params: params
            }
        });
    };
}
export const ACCUSE_TRIGGER = 'ACCUSE_TRIGGER';
export function accuseTrigger(accuseType, itemData){
    return (dispatch, getState) => {
        if(accuseType !== 'none' && getState().accuse.accuseItem[accuseType].length === 0){
            let url = "";

            switch(accuseType){
                case 'activity': 
                    url = '/ajax/accuse/getAccuseItem?type=1';
                    break;
                case 'user':
                    url = '/ajax/accuse/getAccuseItem?type=2';
                    break;
                default: 
                    url = '/ajax/accuse/getAccuseItem?type=1';
            }

            $.get(url, response =>{
                dispatch({
                    type: GETACCUSEITEM,
                    response,
                    accuseType
                });

                dispatch({
                    type: ACCUSE_TRIGGER,
                    accuseType,
                    itemData
                });

            });

        }else{
            dispatch({
                type: ACCUSE_TRIGGER,
                accuseType,
                itemData
            });
        }
    }
}
export const LOADED_PROFILE_GALLERY_SORT = 'LOADED_PROFILE_GALLERY_SORT';
export const loadProfileGallerySort = () => (dispatch, getState) => {
    const activity = getState().activity;

    if(!activity.gallerysort.loading && !activity.gallerysort.end){
        dispatch(requestData('GALLERYSORT'));
        return dispatch({
            'CALL_API': {
                type: LOADED_PROFILE_GALLERY_SORT,
                method: 'get',
                target: '/profile/profileGallery/getGallerySortList',
                params: {}
            }
        }).then((response) => {
            if(response.response){
                return dispatch(receiveData(LOADED_PROFILE_GALLERY_SORT, response.response));
            }else{
                return dispatch(receiveFail(LOADED_PROFILE_GALLERY_SORT, response));
            }
        });
    }else{
        return Promise.resolve();
    }
};
export const INIT_ACTIVITY = 'INIT_ACTIVITY';
export const initActivity = (params) => {
    return {
        type: INIT_ACTIVITY,
        params
    };
}
DerekHung commented 7 years ago

提供 mobile-web 胤廷有經過重新設計的 action


import * as GroupApi from './group_api';
import {loadListDataCenter, initialEntity} from 'src/client/actions/general';
import {isWrong} from 'src/util/checkTools';

const domain = 'group';

/**
 * 當group要取得到非PageModel的資料使用的
 * 目前用於
 *  -   請求取得所有Group的類別queryGroupCategoryList()
 *  - 取得自己的社團的初始資料getMyGroupInitData()(有五大類)
 *
 * @param {object} {domain, key, ...option} - 內涵domain, key, 其餘的會被放入option中
 */
export const REQUEST_GROUP_DATA = 'REQUEST_GROUP_DATA';
export const requestGroupData = ({domain, key, ...option}) => ({
    type: REQUEST_GROUP_DATA,
    payload: {domain, key, ...option},
});

/**
 * 當group接收到非PageModel的資料使用的
 * 目前用於
 *  -   請求取得所有Group的類別queryGroupCategoryList()
 *  - 取得自己的社團的初始資料getMyGroupInitData()(有五大類)
 *
 * @param {object} {domain, key, ...option} - 內涵domain, key, 其餘的會被放入option中
 */
export const RECEIVE_GROUP_DATA = 'RECEIVE_GROUP_DATA';
export const receiveGroupData = ({domain, key, ...option}) => ({
    type: RECEIVE_GROUP_DATA,
    payload: {domain, key, ...option},
});

/**
 * 當group接收非PageModel資料發生錯誤時使用的
 * 目前用於
 *  -   請求取得所有Group的類別queryGroupCategoryList()
 *  - 取得自己的社團的初始資料getMyGroupInitData()(有五大類)
 * @param {object} {domain, key, ...option} - 內涵domain, key, 其餘的會被放入option中
 */
export const RECEIVE_GROUP_DATA_FAIL = 'RECEIVE_GROUP_DATA_FAIL';
export function receiveGroupDataFail({domain, key, option}) {
    return (dispatch) => {
        dispatch({
            type: RECEIVE_GROUP_DATA_FAIL,
            payload: {domain, key, option},
        });
        return Promise.reject(`FAIL [${domain}-${key}]`);
    };
}

/**
 * 切換group的tab
 * 1. 發出切換group tab的action
 * 2. 判斷此分頁(社團類別)是否有載入資料了
 *      -若無則去撈資料,subDomain為all or activity or member需要多設定option,dispatch(loadListDataCenter({...}))
 *
 * @param {string|number} tab - 要切換的分頁名,為Group類別的子項目
 * @param {string} subDomain - 要切換的分頁類別,為'all' 或 'self' 或 'currentChannel'
 * @param {number} channelId - 要切換的社團首頁的channelId
 */
export const CHANGE_GROUP_TAB = 'CHANGE_GROUP_TAB';
export const changeGroupTab = (tab, subDomain, channelId) => (dispatch, getState) => {
    dispatch({
        type: CHANGE_GROUP_TAB,
        payload: {tab, subDomain, channelId},
    });
    /**
     * A. 當subDomain === 'currentChannel'表示在社團獨立頁,須帶channelId
     *      此時的tab會為activity(文章頁)、member(成員頁)
     *
     * B. 當subDomain為all或是self表示在列表頁
     *      此時的tab會為社團分類如'知識技術','品味生活','joined', 'managed'...
     *
     * 要檢查切過去的分頁有沒有撈過資料,沒有的話要去打Api
     */
    if (subDomain === 'currentChannel') {
        if (!getState().entities.channels[channelId][tab].hasLoaded) {
            return dispatch(loadListDataCenter({
                domain: 'group',
                key: tab,
                channelId,
            }));
        }
    } else if (!getState().group[subDomain].byGroup[tab].hasLoaded) {
        return dispatch(loadListDataCenter({
            domain: 'group',
            key: tab,
        }));
    }

    return Promise.resolve('done');
};

/**
 * 進入公開社團時要觸發的action
 * 1. 判斷是否載入過社團列表頁了 Object.keys(getState().group.all.byGroup).length > 0
 *      -無,打GroupApi.queryGroupCategoryList()取得所有Group的類別(目前預設有四大類)
 *      [TODO] 若此API失敗的處理
 * 2. 切換分頁state.group.tab.all到第一個類別
 */
export const initGroupPage = () => (dispatch, getState) => {
    dispatch({type: 'INIT_GROUP_PAGE'});
    const key = 'initGroupPage';
    let dummyPromise;

    if (!Object.keys(getState().group.all.byGroup).length) {
        dummyPromise = () => {
            dispatch(requestGroupData({domain, key}));
            return dispatch(GroupApi.queryGroupCategoryList()).then(({response}) => {
                if (isWrong(response)) {
                    return dispatch(receiveGroupDataFail({domain, key}));
                }
                return dispatch(receiveGroupData({domain, key, response}));
            });
        };
    } else {
        dummyPromise = () => Promise.resolve();
    }

    return dummyPromise()
        .then(() => {
            const firstGroupName = Object.keys(getState().group.all.byGroup)[0];
            return dispatch(changeGroupTab(firstGroupName, 'all'));
        })
        .catch((reason) => { console.info(reason); });
};

/**
 * 進入我的社團時要觸發的action
 * 1. 判斷是否載入過我的社團列表頁了 state.group.self.length > 0
 *      -無,打GroupApi.getMyGroupInitData()取得自己的社團的初始資料(有五大類)
 * 2. 切換分頁state.group.tab.all到第一個類別
 */
export const initMyGroupPage = () => (dispatch, getState) => {
    dispatch({type: 'INIT_MY_GROUP_PAGE'});
    const key = 'initMyGroupPage';
    let dummyPromise;

    if (!Object.keys(getState().group.self.byGroup).length) {
        dummyPromise = () => {
            dispatch(requestGroupData({domain, key}));
            return dispatch(GroupApi.getMyGroupInitData()).then(({response}) => {
                if (isWrong(response)) {
                    return dispatch(receiveGroupDataFail({domain, key}));
                }
                return dispatch(receiveGroupData({domain, key, response}));
            });
        };
    } else {
        dummyPromise = () => Promise.resolve();
    }

    return dummyPromise().then(() => {
        const firstGroupName = Object.keys(getState().group.self.byGroup)[0];
        return dispatch(changeGroupTab(firstGroupName, 'self'));
    });
};

/**
 * 進入社團首頁時觸發的action
 * 1. 進入initSingleGroupInfo這個function,去看entities納的channels是否存在此channelId的資料了
 * 2. 切換group的分頁
 *
 * @param {number} channelId - 要進入的社團的channelId
 */
export const initGroupMainPage = channelId => (dispatch, getState) => {
    dispatch({type: 'INIT_GROUP_MAIN_PAGE'});

    return initSingleGroupInfo(dispatch, getState, channelId)
        .then(() => dispatch(changeGroupTab('activity', 'currentChannel', channelId)));
};

/**
 * 進入社團首頁的成員列表時觸發的action
 * 1. 進入initSingleGroupInfo這個function,去看entities納的channels是否存在此channelId的資料了
 * 2. 切換group的分頁
 *
 * @param {number} channelId - 要進入的社團的channelId
 */
export const initGroupMemberPage = channelId => (dispatch, getState) => {
    dispatch({type: 'INIT_GROUP_Group_PAGE'});

    return initSingleGroupInfo(dispatch, getState, channelId)
        .then(() => dispatch(changeGroupTab('member', 'currentChannel', channelId)));
};

/**
 * 判斷entities內的channels是否已經有此channel的資料
 * 目前只用在initGroupMemberPage與initGroupMainPage
 *
 * @param {function} dispatch - store的dispatch
 * @param {function} getState - store的getState
 * @param {number} channelId - 要進入的社團的channelId
 */
function initSingleGroupInfo(dispatch, getState, channelId) {
    const key = 'initSingleGroup';
    const entity = getState().entities.channels[channelId];

 // 若不存在於entities中或沒載入過,去取得groupInfo並且新增於entities.channels[channelId]
    const dummyPromise = !entity || entity.hasLoaded
        ? () => dispatch(GroupApi.getGroupInfo({channelId}))
                        .then((res) => {
                            const source = isWrong(res.response) ? {} : res.response;
                            dispatch(initialEntity({
                                toEntity: 'channels',
                                domain,
                                key,
                                channelId,
                                source,
                            }));
                        })
        : () => Promise.resolve();
    return dummyPromise();
}
lllllinli commented 7 years ago

*修改已有的機制 1.input、output,有被定義過,類似 data schema

*可以更好的地方:

1.呼叫 api 方法,可以再抽出公用方法 2.錯誤處理流程,統一回傳幾種 type 3.邏輯判斷,另外用方法抽離