一. 前言
现在已经有很多脚手架工具,如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,通常遵循以下组件设计思路:
- 布局组件:仅仅涉及应用UI界面结构的组件,不涉及任何业务逻辑,数据请求及操作;
- 容器组件:负责获取数据,处理业务逻辑,通常在render()函数内返回展示型组件;
- 展示型组件:负责应用的界面UI展示;
- UI组件:指抽象出的可重用的UI独立组件,通常是无状态组件;
展示型组件 | 容器组件 | |
---|---|---|
目标 | UI展示 (HTML结构和样式) | 业务逻辑(获取数据,更新状态) |
感知Redux | 无 | 有 |
数据来源 | props | 订阅Redux store |
变更数据 | 调用props传递的回调函数 | Dispatch Redux actions |
可重用 | 独立性强 | 业务耦合度高 |
五. Redux
现在的任何大型web应用如果少了状态管理容器,那这个应用就缺少了时代特征,可选的库诸如mobx,redux等,实际上大同小异,各取所需,以redux为例,redux是最常用的React应用状态容器库,对于React Native应用也适用。
Redux是一个JavaScript应用的可预测状态管理容器,它不依赖于具体框架或类库,所以它在
多平台的应用开发中有着一致的开发方式和效率,另外它还能帮我们轻松的实现时间旅行,即
action的回放。
- 数据单一来源原则:使用Redux作为应用状态管理容器,统一管理应用的状态树,它推从数据单一可信来源原则,所有数据都来自redux store,所有的数据更新也都由redux处理;
- redux store状态树:redux集中管理应用状态,组织管理形式就好比DOM树和React组件树一样,以树的形式组织,简单高效;
- redux和store:redux是一种Flux的实现方案,所以创建了store一词,它类似于商店,集中管理应用状态,支持将每一个发布的action分发至所有reducer;
- action:以对象数据格式存在,通常至少有type和payload属性,它是对redux中定义的任务的描述;
- reducer:通常是以函数形式存在,接收state(应用局部状态)和action对象两个参数,根据action.type(action类型)执行不同的任务,遵循函数式编程思想
- dispatch:store提供的分发action的功能方法,传递一个action对象参数;
- 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>
)
}
}
未完待续。。。。