React + react-router + react-redux前端架构

首先安装creact-react-app

npm i create-react-app -g

创建APP

create-react-app my-app

cd my-app

先执行 npm eject生成webpack配置文件

Router安装

npm i react-router -s (npm i [email protected] -s)

react-router4.0

提供了Router,Route组件

import {Router,Route} from 'react-router';

import createHashHistory from "history/createHashHistory";

    <Router history={history}>

        <Route path="/" component={App}></Route>

    </Router>

路由嵌套 router4.0嵌套路由写在对应父组件内部

react-router3.0

import {Router,useRouterHistory} from 'react-router';
import {syncHistoryWithStore} from 'react-router-redux';
import {createHashHistory} from "history";
import routes from './containers/routerRegister';

import store from './store';

const routeHistory = useRouterHistory(createHashHistory)();
const history = syncHistoryWithStore(routeHistory, store);

const rootRoute = {
    path:'/',
    component: App,
    childRoutes: routes
};

<Provider store={store}>
    <Router history={history} routes={rootRoute}></Router>
</Provider>

对应的子路由childRoutes

import homeRouter from './Home/router';
import userRouter from './User/router';

const routes = []
	.concat(homeRouter)
	.concat(userRouter);

export default routes;

对应的子路由(如果要实现按需加载需要通过module.export导出一个模块,在routerRegister中使用require()的方式引入对应模块,在webpack中需要修改配置项,此处需要自己百度一波)

import Home from './index';

const routes = [
	{
    	path: 'home',
    	component: Home,
    	// getComponent(nextState, cb) {
    	//     require.ensure([], (require) => {
        //         cb(null, require('./EastPrescribe'))
        //     })
        // }
    }
];

export default routes;

路由传参
在router注册的页面可以使用使用this.props.router对路由进行操作,在自页面下的组件中需要使用hashHistory这个对象去调用router对用的方法,需要从react-router中引入。

import {hashHistory} from 'react-router';
    this.props.router.push({
        pathname:'/page',
        query:{id:'123'}
        // state:{id:'123'} 另外一种方式
        // search: querystring.stringify({id:'123'})  
    });

search:需要在URL上显示的时候可以使用node.js querystring.stringify({}),这种方式可以确保URL方式进入页面时不会报参数错误

路由接受参数

this.props.location.query 
this.props.location.state
querystring.parse(this.props.location.search)

redux和react-redux安装

npm i redux -s
npm i react-redux -s
npm i react-router-redux -s 
npm i redux-actions -s //提供了从reactActions handleActions方法
npm i redux-promise-middleware -s //处理异步
npm i redux-logger -d

index.js

    import {Provider} from 'react-redux';
    import store from './store';
    //设置store的作用域

    <Provider store={store}></Provider>

store

    import {createStore, applyMiddleware, combineReducers} from 'redux';

    import {routerReducer} from 'react-router-redux';

    import promiseMiddleware from 'redux-promise-middleware';

    import reducers from '../reducers';
    

    let middlewares = [];
    

    if (process.env.NODE_ENV !== 'production') {

        let createLogger = require('redux-logger').default;

        middlewares.push(createLogger);

    }

    middlewares.push(promiseMiddleware());

    export default createStore(combineReducers({

        reducers,

        routing: routerReducer  //具体啥意思我也没有弄明白

    }), applyMiddleware(...middlewares))

reducres合并对象

reducers

    import { combineReducers  } from 'redux';

    import AppReducers from '../containers/App/reducers';

    import HomeReducers from '../containers/Home/reducers';



    const reducers = combineReducers({

        AppReducers,

        HomeReducers

    });

    export default reducers;

每个页面对应的actions

        import {createAction} from 'redux-actions';



        export const ACTION_TYPES = {

            GET_INFO: "GET_INFO",

            GET_DETAILS: "GET_DETAILS"

        };



        export const getUserInfo = createAction(ACTION_TYPES.GET_INFO, () => {

            return {userName:'zhangsan'}

        })



        //处理异步

        export const getUserInfo = createAction(ACTION_TYPES.GET_DETAILS, async (params, appId) => {

            let data = await ApiService({ _mt: SYS_APIS.getPatientInfo, ...{ ...params, appId } });

            return data;

        });

每个页面对应的reducers

        import {handleActions} from 'redux-actions';

        import {ACTION_TYPES} from './actions';
        

        const initState = {

            userInfo:{},

            details:{}

        };



        export default handleActions({

            [`${ACTION_TYPES.GET_INFO}`]: (state, action)=>{

                return Object.assign({}, state, {userInfo: action.payload});

            },

            //处理异步需要加完成状态

            [`${ACTION_TYPES.GET_INFO}_FULFILLED`]: (state, action)=>{

                return Object.assign({}, state, {details: action.payload});

            },

        }, initState);

组件中使用redux

        import * as actions from './actions';  // 对应页面的actions

        import { connect } from 'react-redux'; // redux绑定props的方法

        import { bindActionCreators } from 'redux'; // 整合触发dispatch的方法



        //将redux中的state绑定到组件的props中去

        const mapStateToProps = state => {

            return Object.assign({},

                {

                    reducers: {

                        userInfo:state.reducers.AppReducers.userInfo

                    }

                }

            );

        };



        //将改变state的方法绑定到props中去

        const mapDispatchToProps = (dispatch) => {

            return Object.assign({}, {

                actions: bindActionCreators(actions, dispatch)

            });

        };


        //连接props和redux

        export default connect(mapStateToProps, mapDispatchToProps)(App);

方法中使用redux

        取值: let {reducers:{userInfo}} = this.props;

        改值: this.props.actions.getUserInfo();

封装公共请求(具体处理逻辑视具体业务,主体逻辑相同)

基于axios

npm i axios -s

qs请求为post的时候使用formData方式请求

npm i qs -s

定义返回code枚举 (api网关通用异常code)

const STATUS_CODE = {
    '-120': '错误1',	
    '-140': '错误2',	
    '-180': '错误3',
    ...
}

处理全局错误拦截

//===全局错误处理 BEGIN ===//

axios.interceptors.response.use(
    response => {
        'use strict';	
        let {data: { stat }, config } = response;	
        if (config.url === Settings.API) {	
            let errorMsg = '';	
            if (stat.code !== 0 || stat.stateList[0].code !== 0) {
                errorMsg = STATUS_CODE[stat.code] || STATUS_CODE[stat.stateList[0].code] || '系统服务异常, 请稍后重试';
                //登录态异常,引导重新登录
                if (stat.code === -300){
                    // appRelogin();
                }else if (stat.code === -320 || stat.code === -340 || stat.code === -180 || stat.code === -360){
                    // appLogin();
                }	
            }
            if (errorMsg){
                Toast.info(errorMsg);
                return Promise.reject(config.params._mt+':'+errorMsg);
            }
        }
        return response;
    },

    error => {
        'use strict';
        return Promise.reject(error);
    }
);

//===全局错误处理 END ===//

网关请求接口

export default function ApiService(params, userLogin = true, options = {}, externConfig = {silent:false}) {	
    if (!params || typeof params !== 'object') {	
        throw new Error('params is not an object.');	
    }	
    if (!params.hasOwnProperty('_mt') || !params['_mt']) {	
        throw new Error('Miss "_mt"');	
    }	
    let encryptedParams = encrypt(params, userLogin);	 
    let config = Object.assign({}, {
        url: Settings.API,
        method: 'get',
        withCredentials: true
    }, options);

    //post情况下, 以form data模式传递数据
    if (config.method.toLowerCase() === 'post') {
        config.headers = Object.assign({}, (config.headers || {}), { 'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8' });
        config.params = Object.assign({}, (config.params || {}), { _mt: encryptedParams._mt });
        delete encryptedParams._mt;
        config.data = qs.stringify(encryptedParams, { arrayFormat: 'brackets' });
    } else {
        config.params = encryptedParams;
    }

    return axios(config).then(res => {	
        let data = res.data;	
        if (data.content && data.content[0] && data.content[0].hasOwnProperty('success') && !data.content[0].success) {	
            //业务接口异常提示
            let errorMsg = data.content[0].errorMsg;
            if(!externConfig.silent) {
                errorMsg&&Toast.info(errorMsg);
            }
            return Promise.reject(data.content[0]);
        } else {
            return data.content && res.data.content[0] &&  res.data.content[0].value ? res.data.content[0].value : res.data
        }	
    });
}

架构目录
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_37815292/article/details/86229575