基于 React 的前端项目开发总结

原文发表于【抹桥的博客-基于 React 的前端项目开发总结】css

技术选型

咱们的项目主要选用如下技术开发,再配合一些其它辅助工具。html

  • react前端

  • react-routernode

  • reduxreact

  • react-reduxwebpack

开发及线上环境

开发环境

因为项目是先后端分离的,因此咱们须要一套完整的开发环境,须要包括如下功能:nginx

  • 数据 Mockweb

  • Webpack 实施编译刷新redux

  • 方便先后端联调后端

基于这些需求,咱们基于 Express, Webpack, Webpack-dev-middleware 搭建了这套完整的开发环境。

图片描述

能够看到,浏览器全部的请求都被本地的 Node.js 服务拦截。对于静态资源请求,都委托给 webpack-dev-middleware 来处理,对于接口请求根据不一样的环境来决定要作的操做。

本地开发

ENV = 'development' 时,也就是开发环境,那么就直接读取本地的 mock 数据来渲染页面。

先后端联调

ENV = 'api' 时,也就是咱们认为的联调环境,这个时候对于接口请求由 node.js 转发到须要联调的真实后端服务地址上,从而避免直接调用所产生的跨域问题。

这样就能够直接用本地开发代码和后端联调,能大大提升效率,省去了每次须要往服务器上构建部署的步骤。

线上环境

先后端是分开部署的,全部的静态资源都放在 CDN (example.cdn.com)上面。

也就是说咱们的页面在 example.cdn/index.html 这里,可是请求的接口在 example.163.com/api/xxx,咱们确定不能让用户去直接去访问 example.cdn.com/index.html,这样不合理,并且由跨域问题存在。

那么访问 example.dai.163.com 的时候,怎么拿到咱们的 HTML 页面呢?
看下图:

线上环境

在客户端和后台服务之间架设一台 Nginx, 咱们访问的 example.dai.163.com 有两种请求:

  • HTML 页面资源

  • 接口请求

这两种请求都先通过 nginx,在这里作判断,若是是页面请求那么由 nginx 转发到 CDN, 不然交给后端服务来响应接口请求。

拿到页面之后,其它全部的 css, js 等静态资源都是直接请求到 CDN ,这里没什么说的。

数据流转

咱们是借助 redux 来管理数据流的。

数据流转

咱们来看这张图。

首先,经过 middlewarereducer 生成 store, 而后得到项目的初始 state,经过初始 state 去渲染页面的初始状态。

Home 页面为例,首先 Home 经过 react-redux 提供的 connect 方法拿到初始 state 做为 Homeprop 传递给 Home. 而 Home 由多个不一样的子组件组成,这些组件的须要数据再由 Home 经过 props 传递给本身的子组件。

Home 的初始状态加载完毕后,咱们须要向后端请求去拿去一些用户数据。这时,咱们分发一个下面这种格式的 action:

{
  types: ['home/start','home/success','home/failure'],
  payload: {
    api:
    ...
  },
  meta: {
    isApi: true
  }
}

全部的 action 都会按照咱们制定的循序经过一个个 middleware.

在这里,咱们的 action 会被 callApiMiddleware 经过 meta 里面的 isApi 标识命中,并去作相应的事情。

好比在这个中间件里面,咱们去作了真实的接口请求,在请求成功或失败的时候分发对应的 action,以及作一些统一的业务逻辑。好比咱们对后端返回的接口中 code 值有统一的约定,假设 1 为成功, 2 为失败, 3 为未登陆。那么咱们就能够在中间件中去处理这些业务逻辑。

当请求成功,并渲染页面后,假设用户点击了一个按钮,这个按钮须要唤起 native 的一些功能,好比说拍照。那么咱们分发一个唤起拍照功能的 camera/startaction:

{
  types: ['sdk/start','sdk/success','sdk/failure'],
  payload: {
    command:
    ...
  },
  meta: {
    isSDK: true
  }
}

一样的道理,这个 action 会被 EpaySDKMiddleware 所识别并处理,在调起 native 的时候, 为了保证安全性,咱们须要向后发起一个请求去拿签名,这个时候就能够在 EpaySDKMiddleware 里面分发一个接口请求的 action,那么这个 action 一样须要走一遍全部的 middleware. 那么这个接口请求的 action 就会像上面的流程同样,经过 callApiMiddleware 去处理。

中间件的存在,使整个流程变得很是清晰,接口的请求的中间件就只作接口请求,调用 native 接口的中间件就只作对 native 的调用,当对 native 接口的调用须要作后端接口请求的时候,去分发一个 action 走接口请求的中间件。

每一个中间件只专一于本身的事情,既方便后续的维护,同时也提供了一个很好的拓展方式。

一个例子

总体流程

假设咱们由以下的一个路由配置。

{
    component: App,
    path: '/',
    onEnter: initLogin(store),
    indexRoute: {
      getComponent(nextState, cb) {
        require.ensure([], require => {
          cb(null, require('../views/Home').default)
        }, 'Home')
      },
      onEnter: initHome(store)
    },
    childRoutes: [
      createActivateRoute(store),
      {
        path: 'test',
        indexRoute: {
          getComponent(nextState, cb) {
            require.ensure([], require => {
              cb(null, require('../views/Test').default)
            }, 'Test')
          }
        }
      },
      ...
    ]
}

那结合 react-route 咱们来看一个完整的流程。当咱们浏览器里面输入 example.dai.163.com/index.html/#/ 的时候。

首先,经过最上面 线上环境 一节提到的内容,拿到页面须要 html,css,js.

而后渲染 ProvideRouter 组件,分别提供 store 的注入和路由的控制。

此时触发根路径的路由匹配,而后加载根组件 APP, 而后根据路由匹配规则匹配到 IndexRouter, 加载 Home 组件。

后面的事情就和前面数据流转一节讲的是同样的了。

总结

在先后端彻底分离的基础上,借助一套完善的开发环境,能够大大提升的咱们的开发效率,下降先后端联调的成本。

同时借助于 Redux 思想,实现单向数据流,让咱们能够实现一个很是清晰的数据流向。而且,借助于中间件,咱们能够更加有效的控制数据流转的过程。为后面项目的扩展提供无限的想象空间。

相关文章
相关标签/搜索