react 应用架构设计

一. 前言

现在已经有很多脚手架工具,如create-react-app,支持一键创建一个React应用项目结构,很方便,但是享受方便的同时,也失去了对项目架构及技术栈完整学习的机会,而且通常脚手架创建的应用技术架构并不能完全满足我们的业务需求,需要我们自己修改,完善,所以如果希望对项目架构有更深掌控,最好还是从0到1理解一个项目。

二. 技术栈

项目架构搭建很大部分依赖于项目的技术栈,所以先对整个技术栈进行分析,总结:

1. react和react-dom库是项目前提;
2. react路由;
3. 应用状态管理容器;
4. 是否需要Immutable数据;
5. 应用状态的持久化;
6. 异步任务管理;
7. 测试及辅助工具或函数;
8. 开发调试工具;

根据以上划分决定选用以下第三方库和工具构成项目的完整技术栈:

1.react,react-dom;
2.react-router管理应用路由;
3.redux作为JavaScript状态容器,react-redux将React应用与redux连接;
4.Immutable.js支持Immutable化状态,redux-immutable使整个redux store状态树Immutable化;
5.使用redux-persist支持redux状态树的持久化,并添加redux-persist-immutable拓展以支持Immutable化状态树的持久化;
6.使用redux-saga管理应用内的异步任务,如网络请求,异步读取本地数据等;
7.使用jest集成应用测试,使用lodash,ramda等可选辅助类,工具类库;
8.可选使用reactotron调试工具

针对以上分析,完善后的项目结构如图:


三. 开发调试工具

React应用开发目前已经有诸多调试工具,常用的如redux-devtools,Reactron等。

3.1 redux-devtools

redux-devtools是支持热重载,回放action,自定义UI的一款Redux开发工具。

首先需要按照对应的浏览器插件,然后再Redux应用中添加相关配置,就能在浏览器控制台中查看到redux工具栏了,详细文档点此查看。

然后安装项目依赖库:

yarn add --dev redux-devtools

然后在创建redux store时将其作为redux强化器传入
createStore方法:

import
 { applyMiddleware, compose, createStore, combineReducers } from 
'redux'
// 默认为redux提供的组合函数
let composeEnhancers = compose
if
 (__DEV__) {
  
// 开发环境,开启redux-devtools
  
const
 composeWithDevToolsExtension = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
  
if
 (
typeof
 composeWithDevToolsExtension === 
'function'
) {
    
// 支持redux开发工具拓展的组合函数
    composeEnhancers = composeWithDevToolsExtension
  }
}
// create store
const
 store = createStore(
  combineReducers(...),
  initialState,
  
// 组合redux中间价和加强器,强化redux
  composeEnhancers(
    applyMiddleware(...middleware),
    ...enhancers
  )
)
  • 在开发环境下获取redux-devtools提供的拓展组合函数;
  • 创建store时使用拓展组合函数组合redux中间件和增强器,redux-dev-tools便获得了应用redux的相关信息;

3.2 Reactotron

Reactotron是一款跨平台调试React及React Native应用的桌面应用,能动态实时监测并输出React应用等redux,action,saga异步请求等信息。

首先安装:

yarn add --dev reactotron-react-js

然后初始化Reactotron相关配置:

import
 
Reactotron
 
from
 
'reactotron-react-js'
;
import
 { reactotronRedux 
as
 reduxPlugin } 
from
 
'reactotron-redux'
;
import
 sagaPlugin 
from
 
'reactotron-redux-saga'
;
if
 (
Config
.useReactotron) {
  
// refer to https://github.com/infinitered/reactotron for more options!
  
Reactotron
    .configure({ name: 
'React Blog'
 })
    .
use
(reduxPlugin({ onRestore: 
Immutable
 }))
    .
use
(sagaPlugin())
    .connect();
  
// Let's clear Reactotron on every time we load the app
  
Reactotron
.clear();
  
// Totally hacky, but this allows you to not both importing reactotron-react-js
  
// on every file.  This is just DEV mode, so no big deal.
  console.tron = 
Reactotron
;
}

然后启使用 console.tron.overlay方法拓展入口组件:

import
 
'./config/ReactotronConfig'
;
import
 
DebugConfig
 
from
 
'./config/DebugConfig'
;
class
 
App
 
extends
 
Component
 {
  render () {
    
return
 (
      <
Provider
 store={store}>
        <
AppContainer
 />
      </
Provider
>
    )
  }
}
// allow reactotron overlay for fast design in dev mode
export
 
default
 
DebugConfig
.useReactotron
  ? console.tron.overlay(
App
)
  : 
App

至此就可以使用Reactotron客户端捕获应用中发起的所有的redux和action了。

四. 组件划分

React组件化开发原则是组件负责渲染UI,组件不同状态对应不同UI,通常遵循以下组件设计思路:

  1. 布局组件:仅仅涉及应用UI界面结构的组件,不涉及任何业务逻辑,数据请求及操作;
  2. 容器组件:负责获取数据,处理业务逻辑,通常在render()函数内返回展示型组件;
  3. 展示型组件:负责应用的界面UI展示;
  4. UI组件:指抽象出的可重用的UI独立组件,通常是无状态组件;
展示型组件 容器组件
目标 UI展示 (HTML结构和样式) 业务逻辑(获取数据,更新状态)
感知Redux
数据来源 props 订阅Redux store
变更数据 调用props传递的回调函数 Dispatch Redux actions
可重用 独立性强 业务耦合度高

五. Redux

现在的任何大型web应用如果少了状态管理容器,那这个应用就缺少了时代特征,可选的库诸如mobx,redux等,实际上大同小异,各取所需,以redux为例,redux是最常用的React应用状态容器库,对于React Native应用也适用。

Redux是一个JavaScript应用的可预测状态管理容器,它不依赖于具体框架或类库,所以它在
多平台的应用开发中有着一致的开发方式和效率,另外它还能帮我们轻松的实现时间旅行,即
action的回放。
  1. 数据单一来源原则:使用Redux作为应用状态管理容器,统一管理应用的状态树,它推从数据单一可信来源原则,所有数据都来自redux store,所有的数据更新也都由redux处理;
  2. redux store状态树:redux集中管理应用状态,组织管理形式就好比DOM树和React组件树一样,以树的形式组织,简单高效;
  3. redux和store:redux是一种Flux的实现方案,所以创建了store一词,它类似于商店,集中管理应用状态,支持将每一个发布的action分发至所有reducer;
  4. action:以对象数据格式存在,通常至少有type和payload属性,它是对redux中定义的任务的描述;
  5. reducer:通常是以函数形式存在,接收state(应用局部状态)和action对象两个参数,根据action.type(action类型)执行不同的任务,遵循函数式编程思想
  6. dispatch:store提供的分发action的功能方法,传递一个action对象参数;
  7. createStore:创建store的方法,接收reducer,初始应用状态,redux中间件和增强器,初始化store,开始监听action;

5.1 中间件(Redux Middleware)

Redux中间件,和Node中间件一样,它可以在action分发至任务处理reducer之前做一些额外工作,dispatch发布的action将依次传递给所有中间件,最终到达reducer,所以我们使用中间件可以拓展诸如记录日志,添加监控,切换路由等功能,所以中间件本质上只是拓展了 store.dispatch方法。

5.2 增强器(Store Enhancer)

有些时候我们可能并不满足于拓展 dispatch方法,还希望能增强store,redux提供以增强器形式增强store的各个方面,甚至可以完全定制一个store对象上的所有接口,而不仅仅是 store.dispatch方法。

const
 logEnhancer = (createStore) => (reducer, preloadedState, enhancer) => {
  
const
 store = createStore(reducer, preloadedState, enhancer)
  
const
 originalDispatch = store.dispatch
  store.dispatch = (action) => {
    console.log(action)
    originalDispatch(action)
  }
  
return
 store
}

最简单的例子代码如上,新函数接收redux的createStore方法和创建store需要的参数,然后在函数内部保存store对象上某方法的引用,重新实现该方法,在里面处理完增强逻辑后调用原始方法,保证原始功能正常执行,这样就增强了store的dispatch方法。

可以看到,增强器完全能实现中间件的功能,其实,中间件就是以增强器方式实现的,它提供的 compose方法就可以组合将我们传入的增强器拓展到store,而如果我们传入中间件,则需要先调用 applyMiddleware方法包装,内部以增强器形式将中间件功能拓展到 store.dispatch方法

5.3 react-redux

Redux是一个独立的JavaScript应用状态管理容器库,它可以与React、Angular、Ember、jQuery甚至原生JavaScript应用配合使用,所以开发React应用时,需要将Redux和React应用连接起来,才能统一使用Redux管理应用状态,使用官方提供的react-redux库。

class App extends Component
 {
  render () {
    
const
 { store } = this.props
    
return
 (
      <Provider store={store}>
        
<div>
          <Routes/>
</div>
      </Provider>
    )
  }
}

未完待续。。。。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,639评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,277评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,221评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,474评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,570评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,816评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,957评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,718评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,176评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,511评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,646评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,322评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,934评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,755评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,987评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,358评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,514评论 2 348

推荐阅读更多精彩内容