原文发表于【抹桥的博客-基于 React 的前端项目开辟总结】
手艺选型
我们的项目重要选用以下手艺开辟,再配合一些别的辅助工具。
react
react-router
redux
react-redux
开辟及线上环境
开辟环境
因为项目是前后端星散的,所以我们须要一套完整的开辟环境,须要包含以下功用:
数据 Mock
Webpack 实行编译革新
轻易前后端联调
基于这些需求,我们基于 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 来治理数据流的。
我们来看这张图。
起首,经由历程 middleware
和 reducer
天生 store
, 然后取得项目的初始 state
,经由历程初始 state
去衬着页面的初始状况。
以 Home
页面为例,起首 Home
经由历程 react-redux
供应的 connect
要领拿到初始 state
作为 Home
的 prop
传递给 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/start
的action
:
{
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.
然后衬着 Provide
和 Router
组件,离别供应 store
的注入和路由的掌握。
此时触发根途径的路由婚配,然后加载根组件 APP
, 然后依据路由婚配划定规矩婚配到 IndexRouter
, 加载 Home
组件。
背面的事变就和前面数据流转一节讲的是一样的了。
总结
在前后端完整星散的基础上,借助一套完美的开辟环境,能够大大提高的我们的开辟效力,下降前后端联调的本钱。
同时借助于 Redux 头脑,完成单向数据流,让我们能够完成一个异常清楚的数据流向。而且,借助于中间件,我们能够越发有用的掌握数据流转的历程。为背面项目的扩大供应无穷的设想空间。