前言
一个完整的React项目,包含许多优秀的技术库支持,它的数据流,可以通过flux/redux管理,它的路由配置:react-router,它的包管理、测试
以及组件编写(ES6),接下来会对这些相关技术做一些深入的了解和整理,持续更新中。
1. WebPacket
webPacket
webpacke是一个前端模块管理和打包工具,通过使用Webpack,能够像Node.js一样处理依赖关系,然后解析出模块之间的依赖,将代码打包。
webpacket将项目中用到的一切静态资源都视为模块,模块之间互相依赖。webpacket对其进行统一的管理以及打包发布。
webpack-dev-server是一个小型的node.js Express服务器,它使用webpack-dev-middleware中间件来为通过webpack打包生成的资源文件提供Web服务。它还有一个通过Socket.IO连接着webpack-dev-server服务器的小型运行时程序。webpack-dev-server发送关于编译状态的消息到客户端,客户端根据消息作出响应。
简单来说,webpack-dev-server就是一个小型的静态文件服务器。使用它,可以为webpack打包生成的资源文件提供Web服务。NPM (http://www.runoob.com/nodejs/nodejs-npm.html‘>详情参考)
NPM的全称是Node Package Manager,它是Nodejs的包管理器。Nodejs自身提供了基本的模块。但是在这些基本模块上 开发实际应用需要较多的工作。NPM上已经有了很多Nodejs库或框架,这些库从各个方面可以帮助Nodejs的开发者完成较为复杂的应用。
package.json
Package.json 属性说明: name - 包名。 version - 包的版本号。 description - 包的描述。 homepage - 包的官网 url 。 author - 包的作者姓名。 contributors - 包的其他贡献者姓名。 dependencies - 依赖包列表。如果依赖包没有安装,npm 会自动将依赖包安装在 node_module 目录下。 repository - 包代码存放的地方的类型,可以是 git 或 svn,git 可在 Github 上。 main - main 字段是一个模块ID,它是一个指向你程序的主要项目。就是说,如果你包的名字叫 express,然后用户安装它,然后require("express")。 keywords - 关键字
webPacket 配置
来看一个最简单的webPacket配置: webPacket.config.js
module.exports = { entry:[ './app/main.js' //定义打包后的入口文件 ], output: { //定义输出文件位置 path: __dirname + '/assets/', //打包文件存放绝对路径 publicPath: "/assets/", //网站运行时的访问路径 filename: 'bundle.js' //打包后的文件名 } };
webPacket 模块加载器(Loaders)
安装加载器命令:
$ npm install xxx-loader --save 例如: 安装css加载器 npm install css-loader style-loader --save-dev
安装后,会自动同步到package.json文件中。
在webpack.config.js中配置loader:
module: { loaders: [ {test: /\.css$/, loaders: ['style', 'css']}, {test: /\.less$/, loaders: ['style', 'css', 'less']} ] }
其中,test里包含一个正则,包含需要匹配的文件。loaders是一个数组,包含要处理这些程序的loaders,这里要注意loaders处理的顺序是从右往左的。
也可以用webpack来处理图片和静态文件
安装url-loader npm install url-loader --save-dev 配置config文件 { test: /\.(png|jpg)$/, loader: 'url?limit=40000' //limit参数,当图片大小超过这个限制的时候,会启用base64编码图片 }
添加ES6支持:
可以通过babel配置,添加对ES6语法的支持
2. Redux
React的核心是使用组件定义界面的表现,是一个View层的前端库,那么在使用React的时候我们通常还需要一套机制去管理组件与组件之间,组件与数据模型之间的通信。
介绍
随着Javascript单页应用开发日趋复杂,javascript需要管理比任何时候都要多的状态,管理这些不断变化的state十分困难。**state在什么时候,由于什么原因,如何变化已然不受控制。**Redux就是为了处理React中state数据的问题而出现的,它试图让state的变换变得可预测。
三大原则
单一数据源
整个应用的state被储存在一颗object tree中,并且这个object tree只存在于唯一一个store中。
state是只读的
唯一改变state的方法就是触发action,action是一个用于描述已发生事件的普通对象。
这样就确保了所有state的修改都被集中化处理,视图和网络请求不能直接修改state,只能表达想要修改的意图。
使用纯函数进行修改
为了描述action如何改变state tree,需要编写reducers.
Reducer只是一些纯函数,它接受先前的state和action,并返回新的state。
redux和flux
flux是Facebook建立客户端web应用的前端架构,它通过利用一个单向的数据流补充了React的组合视图组件。
Redux 的灵感来源于 Flux 的几个重要特性。和 Flux 一样,Redux 规定,将模型的更新逻辑全部集中于一个特定的层(Flux 里的 store,Redux 里的 reducer)。Flux 和 Redux 都不允许程序直接修改数据,而是用一个叫作 “action” 的普通对象来对更改进行描述。
不同于flux,redux没有调度器。它依赖纯函数来替代事件处理器。纯函数构建简单,也无需用额外的实体来管理它们。
Redux
Action
Action是把数据从应用传到store的有效载荷,是store数据的唯一来源。
Action本质是javascript普通对象。Redux中的action是纯函数,没有任何副作用。
Reduce
Action只是描述了有事情发生这一事实,并未指明应用如何更新state,更新state是reducer要做的事情。
应用所有的state都被保存在一个单一的对象中(state树)。
对于Action和Reducer,它们有明确的分工
Action -> 干了什么,数据如何变化
Reducer -> 更新state状态Store
我们已经知道action用来描述发生了什么,reducers根据action更新state。
Store就是把他们联系到一起的对象,Store有以下职责:
- 维持应用的state
- 提供getState( ) 方法获取state
- 提供dispatch(action) 方法更新state
- 通过subscribe(listener)方法注册监听器
Reduce应用只有一个单一的store, 需要拆分处理数据的逻辑时,用render组合而不是创建多个store。
数据流
严格的单向数据流是Redux架构设计的核心。这意味着应用中的所有数据都遵循着相同的生命周期,使应用变得更加可预测和容易理解。
Redux应用中数据的声明周期遵循下面四个步骤:
调用store.dispatch(action)
Action就是一个描述发生了什么的普通对象:
{ type: 'LIKE_ARTICLE', articleId: 42 }; { type: 'FETCH_USER_SUCCESS', response: { id: 3, name: 'Mary' } }; { type: 'ADD_TODO', text: 'Read the Redux docs.'};
可以在任何地方调用store.dispatch(action)
Redux store 调用传入的reducer函数
Store会把两个参数传入reducer: 当前的state树和action。
function getClientHistorySuccess (state, action) { return _.extend({}, state, { histories: action.histories, getHistoryLoading: false }); }
注意reducer是纯函数。它仅仅用作计算下一个state,它应该是完全可预测的:多次传入相同的输入必须产生相同的输出。它不应做有副作用的操作,如 API 调用或路由跳转。这些应该在 dispatch action 前发生。
根 reducer 应该把多个子 reducer 输出合并成一个单一的 state 树。
根 reducer 的结构完全由你决定。Redux 原生提供combineReducers()辅助函数,来把根 reducer 拆分成多个函数,用于分别处理 state 树的一个分支。
Redux store 保存了根 reducer 返回的完整 state 树。
搭配React
beginning
Redux 默认并不包含 React 绑定库,需要单独安装。
npm install --save react-redux
容器组件和展示组件
Redux 的 React 绑定库包含了 容器组件和展示组件相分离 的开发思想。
明智的做法是只在最顶层组件(如路由操作)里使用 Redux。其余内部组件仅仅是展示性的,所有数据都通过 props 传入。
容器组件 展示组件 Location 最顶层,路由处理 中间和子组件 Awesome of redux 是 否 读取数据 从Redux获取state 从props获取数据 修改数据 向Redux派发actions 从props调用回调函数 接下来就是具体的组件编写工作,主要的组件编写完成后,需要连接到redux
首先,需要获取从之前安装好的 react-redux 提供的 Provider,并且在渲染之前将根组件包装进 。
let rootElement = document.getElementById('root') render( <Provider store={store}> <App /> </Provider>, rootElement )
这使得 store 能为下面的组件所用。
接着,通过 react-redux 提供的 connect() 方法将包装好的组件连接到Redux。尽量只做一个顶层的组件,或者 route 处理。
任何一个从 connect() 包装好的组件都可以得到一个 dispatch 方法作为组件的 props,以及得到全局 state 中所需的任何内容。 connect() 的唯一参数是 selector。此方法可以从 Redux store 接收到全局的 state,然后返回组件中需要的 props。最简单的情况下,可以返回一个初始的 state (例如,返回认证方法),但最好先将其进行转化。
3. react-route
解决复杂的URL和层级组件之间的映射关系是React Router的核心。我们使用声明式的方式引入路由。使用JSX方式来进行路由的配置。这样就可以通过属性的方式来配置页面视图的层级关系。
路由配置
var Router = require('react-router'); var Route = Router.Route; var routes = ( <Route handler={App}> <Route path="about" handler={About}/> <Route path="inbox" handler={Inbox}/> </Route> );