俺好像看懂了公司前端代码

开发 前端
今天的重点是React或React Native如何高效管理调用后端接口,和上篇讲到Vue管理后端接口一样,它们有很多相似性,也有不同之处,因为我们知道它们开发模式和方法有些不同。

他来了,他来了,

他掉着头发走来了。

大家好,我是前端开发者卜壮,经过笔者上篇《俺咋能看懂公司前端项目?》之后,不知道大家有没有学到其设计思想并应用到自己的项目中。我相信你们,肯定没有。

 

[[328644]]

趁着头发茂密,让我们步入正题!

今天的主角React,它作为当今社会的前端主流框架,在前端框架江湖中算是一哥的存在,凭借小巧高效灵活等特点,完成了众多企业级的大项目,并且衍生了很多其他的框架,比如像跨平台移动开发React Native,它的一套代码可以运行在Android和iOS。然而这些都不是本篇文章的重点。

 

[[328645]]

今天的重点是React或React Native如何高效管理调用后端接口,和上篇讲到Vue管理后端接口一样,它们有很多相似性,也有不同之处,因为我们知道它们开发模式和方法有些不同。

起初的想法,Vue有自己单独的状态管理器Vuex,React也可以用Redux来管理状态;Vue提供了混入(mixins)的开发方式,虽然React起初也有混入的功能,后来被舍弃掉了,但是React可以通过高阶组件来实现混入的功能。基于这些想法,该出手时就出手,风风火火参北斗啊。

后来,我终于学会了让自己爱自己,搞错了,我终于学会了Redux以及React-redux,学起来其实和Vuex一样,只是有些概念不一样。

Vuex里面有State定义状态、Mutation修改状态、Action支持异步调用Mutation修改状态、Getter从State派生状态。

而在Redux中主要有Reducer和Action,Reducer是一个纯函数,根据不同的Action返回不同的状态,Action则是用于改变状态唯一途径。但是仅靠Redux提供的功能只支持同步修改状态,但是Redux有很多中间件,其中Redux-thunk就是一个支持异步的中间件,因为使用Redux管理请求需要异步支持,所以,I want you。

 

[[328646]]

哆来咪发梭拉稀

又唱上了。

前面说了那么多都是凑字数,

下面开始我们的步骤。

首先先了解一下前端管理后台接口的架构设计流程,技术选型后端要使用Swagger接口管理,前端React使用Redux状态管理,React-redux状态映射组件Props,Redux-thunk支持异步管理状态,解析Swagger需要用到Handlebars模板编译和fs文件解析。

 

俺好像看懂了公司前端代码

1、引入swagger。

后台接口服务器引入swagger。这一步就不多说了,你有我有全都有啊,诶嘿,诶嘿,参北斗啊。

2、解析swagger生成controller。

可以通过js写一个脚本生成指定格式的js文件。swagger提供的v2/api-docs网址可以访问接口的json。这个json是一个固定格式的字符串,包含tags数组和path对象。通过Handlebars模板编译和fs文件解析生成以下格式的js文件,每个类对应一个文件。同时生成一个index.js入口文件,将所有的controller文件集中装饰处理。

  1. export default{     
  2.   actions: {         
  3.     findById : {             
  4.       summary: '按主键查询',             
  5.       method: 'get',             
  6.       url: (payload) => `/api/user/${payload.id}`,             
  7.       parameters: [{'name':'id','in':'path','description':'id','required':true,'type':'string'}],        
  8.     },    
  9.   },} 

3、为每个controller文件生成对应的actions和reducers函数。

上述所说的入口文件index.js用来装饰每一个controller,装饰的内容就是遍历controller文件的actions对象,生成actions函数和reducers纯函数。最后将生成的reducers交给redux管理,actions则为组件提供调用。actions函数里面有三步,包括请求前,请求中和请求后对状态的处理。这三步是为了设置接口请求的loading状态,通过loading状态来处理页面的加载效果,省去在组件中自定义的逻辑判断。下图为每个接口在action函数的数据处理。

 

俺好像看懂了公司前端代码

生成action和reducer的代码:

  1. export default (name, controller) => {     
  2.   const defaultState = (type) => ({//设置请求前的数据状态,生成reducer时使用        
  3.     type: type,         
  4.     loading: false,         
  5.     error: null,         
  6.     request: null,         
  7.     data: {},     
  8.   })     
  9.   const start_request = (type) => ({//设置开始请求的数据状态        
  10.     type: type,         
  11.     loading: true,         
  12.     error: null,         
  13.     request: null,         
  14.     data: {},     
  15.   })     
  16.   let actions = {}     
  17.   let reducers = {}    //遍历生成的controller文件的actions     
  18.   _.forEach(_.keys(controller.actions), key => {         
  19.     const action = controller.actions[key]         
  20.     //生成action         
  21.     actions[`${name}_${key}`] = (payload) => {             
  22.       return async (dispatch) => {                 
  23.         //设置开始请求的数据状态                 
  24.         dispatch(start_request(`${name}_${key}`))                 
  25.         //开始网络请求                
  26.         let resp = {}                 
  27.         try {                     
  28.           resp = await ajaxUtil.myRequest(action, payload)                 
  29.         } catch (e) {                     
  30.           resp = e                }                 
  31.         let handleResult = null                
  32.         //数据处理,这里对resp.status状态码为400-500的错误处理,和200-300的成功数据处理                 
  33.         if (!resp) {                     
  34.           handleResult = {                         
  35.             type: `${name}_${key}`,                        
  36.             loading: false,                       
  37.             error: '系统错误',                       
  38.             data: null,                     
  39.           }                
  40.         } else if (resp.status >= 400 && resp.status < 500) {                     
  41.           handleResult = {...}                 
  42.                          } else if (resp.status >= 500) {                    
  43.                            handleResult = {...}                 
  44.                                           } else if (resp.status >= 200 && resp.status < 300) {                    
  45.                                             handleResult = {                        
  46.                                               type: `${name}_${key}`,                        
  47.                                               loading: false,                        
  48.                                               error: null,                        
  49.                                               request: payload,                         
  50.                                               data: resp.data,                     
  51.                                             }                 
  52.                                           }                 
  53.                            //请求结束数据状态处理                 
  54.                            dispatch(handleResult)                 
  55.                            return handleResult            
  56.                          }         
  57.         }         
  58.         //生成reducer         
  59.         reducers[`${name}_${key}`] = (state = defaultState(`${name}_${key}`), action) => {             
  60.           if (action.type === `${name}_${key}`) {                 
  61.             return {...state, ...action}             
  62.           } else {                 
  63.             return state             
  64.           }         
  65.         }     
  66.       })     
  67.       return {...actions, reducers} 
  68.     } 

4、封装高阶组件,将接口请求状态数据映射到组件的props中。

vuex里面有四个辅助函数这个react-redux要登场了。react-redux提供了一个connect,它是一个高阶组件,接收 React 组件作为输入,输出一个新的 React 组件。高阶组件让代码更具有复用性、逻辑性与抽象特征。可以对 render 方法作劫持,也可以控制 props 与 state。我们这里需要自己封装一个高阶组件,里面调用react-redux提供的connect函数将state和dispatch映射到组件的props,此外还需要定义两个函数映射到props中,一个是用于调用接口的函数,另一个是获取请求接口的loading状态函数。最后返回一个新的组件。

高阶组件封装如下:

  1. export default function connect(states = null, dispatches = null) {     
  2.   return (WrappedComponent) => {         
  3.     const mapStateToProps = state => {             
  4.       //该函数用于获取网络请求的loading,用于组件显示加载中的指示             
  5.       const loading = (scope) => {                 
  6.         return state[`${scope.controller}_${scope.method}`].loading             
  7.       }            
  8.       return states ? {...state, ...states(state), loading} : {...state, loading}         
  9.     }         
  10.     //集中处理请求发送的异常         
  11.     const error = (cbData) => {             
  12.       //判断cbData.error,用来alert()提示用户错误信息         
  13.     }         
  14.     const mapDispatchToProps = dispatchAsync => {             
  15.       //该函数用于组件中发起网络请求            
  16.       const dispatch = async (scope, payload) => {                
  17.         const controller = Controller[scope.controller]                 
  18.         let cbData = await dispatchAsync(controller[`${scope.controller}_${scope.method}`](payload))                 
  19.         error(cbData)                 
  20.         return cbData             
  21.       }             
  22.       return dispatches ? {...dispatches(dispatchAsync), dispatch} : {dispatch}        
  23.     }         
  24.     //reduxConnect是react-redux提供的,原名称是connect,我这里起了个别名,为了避免和我封装的高阶组件名冲突         
  25.     //import {connect as reduxConnect} from 'react-redux'         
  26.     const Root = reduxConnect(mapStateToProps, mapDispatchToProps)(WrappedComponent)         
  27.     return class HOC extends React.Component {             
  28.       render() {                
  29.         return <Root {...this.props}/>             
  30.       }         
  31.     }    
  32.   }}​ 

5、组件引用自定义的高阶组件。

如果组件涉及到网络请求,可以引入。引入之后像这样:

export default connect(mapStateToProps, mapDispatchToProps)(Home),其中Home是组件,mapStateToProps和mapDispatchToProps是想要指定映射哪些数据到props中,可以不传。

然后就可以为所欲为了,发起网络请求this.props.dispatch(IUserController.findById,{id}),返回值是请求后的数据。获取请求状态this.props.loading(IUserController.findById),返回值是true或false。

上文我着重说的是react如何管理调用接口,其实react native设计是一模一样的,大伙不妨试着设计一下。

许多事,

都是要经过不断尝试才会成功的。

这篇内容就到这里,我们下篇再见。

责任编辑:未丽燕 来源: 今日头条
相关推荐

2021-10-28 19:35:02

代码main方法

2023-06-27 07:09:39

2022-06-28 08:42:03

磁盘kafka高性能

2022-11-28 07:10:57

2017-10-18 12:41:50

PC市场电脑潜规则

2024-03-05 18:19:07

localhostLinux数据库

2011-09-02 16:08:09

Sencha ToucAPI文档

2019-05-16 09:38:04

Redis高可用数据

2018-01-04 00:10:52

物联网技术信息

2017-04-13 14:54:56

互联网

2021-04-26 10:30:43

USB4设备Thunderbolt

2022-03-18 00:17:30

NISTICS安全

2017-01-12 14:52:51

代码

2019-11-20 15:40:48

CPU软件处理器

2020-06-05 18:32:41

HBaseQAQHDFS

2018-07-09 14:24:32

区块链

2014-12-02 10:11:21

硅谷程序员比例

2020-05-15 14:30:23

前端浏览器架构

2014-12-02 10:09:05

硅谷比例

2021-04-12 10:52:10

InnoDB索引数据库
点赞
收藏

51CTO技术栈公众号