• 基于React+Router+Redux+Sagas+fetch+ant Design +less + es6+mockjs的项目过程总结


    app.js是首页面,路由放此。
    sagas在此页面被引用。
     
    import rootSaga from './sagas'
    const store = configureStore(initialState)
    store.runSaga(rootSaga); 

    1)FL.js    
    修改对应的接口Path值,便于后期对接口地址的管理。
    SupSearch:'/api/Order/supSearch.json',
    SupState:'/api/Order/supState.json',
    2)sagas  
    中间件,只会在应用启动时调用(但初始启动的sagas可能会动态的调用其它sagas),用于监听发起的action,然后决定这个action用来做什么。
    如:1.发起一个异步调用(ajax请求) 2.发起其它的action到store。 3.调用其它的sagas
     
    index.js里面放所有的sagas。
    import { watchGetAccountSaga } from './account'
    import {supSearch} from './supSearch'
    export default function* rootSaga() {
        yield [
            // 更多
            watchGetAccountSaga(),
            supSearch(),
        ]
    }
    子saga:有两个Generator函数。其中一个通过while(true),take方法来一直监听action。
    只有当此事件被dispatch则fork第二个Generator函数。(此步骤避免了同时发起多个不必要的请求。
    只有当view页面componentWillMount 才触发此action,发起请求。)
    componentWillMount(){  
            this.props.initialDispatch()
        },
    import { SUPSEARCHACTION, supSearchSucceed,supSearchFailed} from '../actions/sup'
    export function* supSearch() {
        while (true) {
            yield take(SUPSEARCHACTION)
            yield fork(fetchSupSearchApi)
        }
    }
    第二个Generator方法主要用来生成fetch请求。
    任务要被beginTask和endTask包裹。在请求成功之后,将请求到的数据dispatch一个对应的action(成功:supSearchSucceed(res) ) 失败(supSearchFailed(e) )。
     
    function* fetchSupSearchApi(){
        try {
            yield put( beginTask() )
            const response = yield call(fetch, FL.PATH.API.SupSearch)
            const res = yield response.json()
            if (!res) {
                return false
            } else {
                yield put( supSearchSucceed(res) )   (成功)
            }
        } catch (e) {
            yield put( supSearchFailed(e) )   (失败)
        } finally {
            yield put( endTask() )
        }
    }
    mockjs也是放在此文件中。
     
    // mock 代码放在 __DEBUG__ 代码块内,生产环境会删除代码块
    if (__DEBUG__) {
        let data = Mock.mock({
            'Status': '200',
            'Position': '001',
            'ErrorCode': '001',
            'Data|1-10': [{
                'productNumber': /[A-Z][A-Z]d{3}[a-z]d{3}/,
                'productName': '@ctitle(3, 5)',
                'supplierName': '@ctitle(3)',
                'productStockStatus|1-100': 1,
                'faceValue|1-1000': 1,
                'productPrice|1-100': 1,
                'type|1-4': 1,
                'averageChargeTime':'@natural(0,200)'+'min',
                'complaintRate':'@natural(0,100)'+'%',
                'successRate': '@natural(0,100)'+'%',
                'today|1-100': 1,
                'week|1-1000':1 ,
                'month|1-10000': 1,
                'purchaseApplyStatus': '@boolean()'
            }]
        });
     
        fetchMock.mock(FL.PATH.API.SupSearch, data);
        // fetchMock.mock(FL.PATH.API.ACCOUNT, 404);
    }
    3)action
    在对应的action文件sup.js中,
     
    export const SUPSEARCHACTION = 'SUPSEARCHACTION'
    export const SUPSEARCH_SUCCEED = 'SUPSEARCH_SUCCEED'
    export const SUPSEARCH_FAILED = 'SUPSEARCH_FAILED'
    分别对应触发,请求成功、请求失败的action:
    export function supSearchAction(){
        return {
            type:SUPSEARCHACTION
        }
    }
    export function supSearchSucceed(items){
        return {
            type:SUPSEARCH_SUCCEED,
            items
        }
    }
    export function supSearchFailed(error) {
        return {
            type: SUPSEARCH_FAILED,
            error,
        }
    }
     
    4)reducer
    index.js中为总reducer。通过import将各个reducer引入进来,通过combineReducer将各个子reducer结合起来。configureStore.js中引入此rootReducer。
     
    import supSearch from './supSearch'
    import supState from './supState'
     
     
    const rootReducer = combineReducers({
        routing: routerReducer,
        supSearch,
        supState,
    })
     
    export default rootReducer
    将action的三种type值引入,触发不同的type值会有不同的处理。
    1、当触发SUPSEARCHACTION时,将isfetching设为true,代表开始请求数据。
    2、当触发SUPSEARCH_SUCCEED时,将isfetching设为false,代表请求完成,成功,并将请求到的参数返回给items,items的值同步到state当中。
    3、当触发SUPSEARCH_FAILED时,将isfetching设为false,代表请求完成,失败。返回错误。
    import {SUPSEARCHACTION,SUPSEARCH_SUCCEED,SUPSEARCH_FAILED} from '../actions/sup'
     
    export default function supSearch (state = {}, action) {
        switch (action.type) {
            case SUPSEARCHACTION:
                return {
                    ...state,
                    isfetching:true,
                }
            case SUPSEARCH_SUCCEED:
                return {
                    ...state,
                    isfetch:false,
                    items: action.items,
                }
            case SUPSEARCH_FAILED:
                return {
                    ...state,
                    isfetching: false,
                    error: action.error,
                    };
            default:
                return state
        }
    }
     
    5)containers
    用于将state进行处理,处理好的数据通过connect传递给component中的view页面  涉及到reselect(创建选择器)。
     
    import { connect} from 'react-redux'  
    import SupSearch from '../components/SupSearch/js/SupSearch'
    import {supSearchAction} from '../actions/sup' 
    import {createSelector } from 'reselect'
     
    const defaultValue = [];
    const stateItemSelector = (state) =>state.supSearch.items || defaultValue
    const stateSelector = createSelector (
        [stateItemSelector],
        (stateItem) => {
            return stateItem
        }
    )
    const mapStateToProps = (state) =>{
        return {
            items:stateSelector(state),
        }
    }
    const mapDispatchToProps = (dispatch) =>{
        return {
            initialDispatch(){
                dispatch(supSearchAction())
            },
        }
    }
    export default connect(
        mapStateToProps,
        mapDispatchToProps
    )(SupSearch)
    6)component
    此部分即为view模块。只有当组件即将被渲染时,才发起action,触发saga部分的yield take(SUPSEARCHACTION)
    initialDispatch方法即为5)中mapDispatchToProps传过来的方法。
     
    componentWillMount(){
            this.props.initialDispatch()
        },
     
     
     
  • 相关阅读:
    android部分控件应用解析
    CodeForces Round #179 (295A)
    面试题27:连续子数组的最大和
    java写文件时,输出不完整的原因以及解决方法
    序列化和反序列化--转
    Java多线程编程那些事:volatile解惑--转
    转变--一个平凡人的2017年总结及2018年展望
    系列文章--批处理学习
    set命令
    bat计算两个时间差
  • 原文地址:https://www.cnblogs.com/mian-bread/p/6094126.html
Copyright © 2020-2023  润新知