React 项目工程介绍
node_modules
所有依赖包所在位置。执行 yarn install
或 npm install
后,会生成此文件夹。
Yarn 或 Npm 包管理器
包管理器,可以类比于 java 的 maven,python 的 pip
yarn.lock
版本号锁定,为了跨机器安装保持一致的版本
package.json
包管理描述文件,使用yarn或npm时自动生成,描述项目名称、项目版本、项目依赖等信息。
webpack.*.js 文件
webpack 配置文件,webpack 是一个 js 应用程序的模块打包器,它将递归的查找模块的依赖关系,并最终打包成一个js文件,通常是一个,在 webpack 下,任何文件都是一个模块。
.babelrc 文件
babel 配置文件,因 react 中使用新的 Es6 语法及 Jsx,所以需要使用工具转换成Es5的语法,以提高浏览器兼容性。
.editorconfig 文件
编辑器风格配置,为了保持统一的编码风格,比如说:trim_trailing_whitespace=true,去除所有多余空格
.eslintrc.js 文件
javascript 代码检查工具 eslint 配置文件,为保持统一的代码规范。
.postcssrc.js 文件
postcss 配置文件,postcss 是一个使用 js 插件处理 styles 的工具, 比如说比较流行的 autoprefixer
插件补充 CSS 前缀。
browserslist 文件
autoprefixer 运行时会依据这个文件中配置的浏览器版本,添加相应的 css 前缀。
deploy.js 文件
自定义的发布脚本文件,将编译打包后的资源 js、css、html 发到七牛 cdn 上。
src
项目源代码位置,平时写项目也基本只要动这个。
项目架构
- index.html 落地页
- main.js、provider.js 真实dom和虚拟dom链接、热加载重渲染
- store.js 配置redux的store
- reducers.js 所有reducer的合并文件
- routers.js 所有路由配置文件
目前大多数 redux 开发者所推荐的项目架构有:
Rails-style
: “actions”、“constants”、“reducers”、“containers” 以及 “components” 分属不同的文件夹- domain-style: 为每个功能或者域创建单独的文件夹,可能会为某些文件类型创建子文件夹
- “Ducks”:类似于 Domain-style,但是明确地将 action、 reducer 绑定在一起,通常将它们定义在同一文件内。
目前我们公司使用的是,dock 模式,但当 action 较多时,会偏向 domain-style 模式,所以是 dock 和 domain-style 混合的。
大家看到的两个文件夹:
- app: 会放一些公共的组件、样式、整个layout
- home: 某个具体项目(home只是举例),以后开发某项功能,以文件夹进行区分。
开发一个项目功能时
一般而言一个项目文件夹会包含:
- containers 文件夹: 包含各个子container
- components 文件夹: 包含项目中复用的或纯展示的组件
- action.js 文件: 包含所有项目的action
- reducer.js 文件: 包含所有reducer, 与action对应, action函数比较少时,可以考虑将reducer、action合并成一个文件。
- index.js 可以作为所有 containers 的入口文件
需要注意
处理 reducer 时
请返回一个新的更新后的对象,而不是直接去修改原始的 state tree
// 直接修改
switch(type) {
case 'COUNTER_INCREMENT':
state.total += 2;
return state;
default:
...
}
// 返回更新后的新对象,对然来对象无影响
switch(type) {
case 'COUNTER_INCREMENT':
const { total } = state;
state = { ...state, total: total + 2 }
return state;
default:
...
}
解释下:
不可变数据 immutable
可变数据带来的问题
- redux 中考虑性能问题,对对象使用浅比较,即不会对深层嵌套的对象进行逐级比较,这会导致对象或数组的数据改变后,组件不会重新 render
- 对于时间旅行,redux-dev-tools 调试工具期望能回放 state 的记录,但一些突变的数据会导致历史 state 的改变。
const a = { orderIds: [1, 2, 3, 4] }
const oldA = a;
a.orderIds.push(5);
console.log(oldA === a); // true, 数据没有更新
创建不可变数据
- 使用对象或数组的扩展运算符
const state = { orderList: [1, 2, 3] }
// 使用扩展运算符产生新对象
state = {
...state,
orderList: [
...orderList,
4,
],
}
- 使用工具库 dot-prop-immutable
import dotProp from 'dot-prop-immutable'
const state = { orderList: [1, 2, 3] }
// 合并/添加
dotProp.merge(state, 'orderList', [4, 5])
// 修改值
dotProp.set(state, 'orderList', [6, 6, 6])
- 使用 immutableJs
完全的 immutable,结构共享,可节省内存,但有学习成本,与原生js混合操作需要转换
创建 actions 时
使用 redux-actions 创建符合的 flux 标准的 action,免去中间的 mutationType
promise 使用参考
优点:
- 更好的回调、异步处理
- 更好的异常处理
缺点:
- 没有获取状态的方法
- 一个 promise 一旦执行,结果有且只有两个,resolve 成功和 reject 失败,不可中断
- 有些浏览器不支持,如需支持要提供 polyfill
fetch 使用参考
基于 promise 的网络请求库
优点:
- 不同于基于事件的 ajax,fetch 是基于 promise 的。
- 构造请求、回调处理更方便,并支持链式调用
- 同构,可跨浏览器和 node 服务端使用方便
缺点:
- 请求一旦发出,不能取消
- 不能设置请求超时时间
- 不能跟踪上传进度,如没有 xhr 的 progress 事件
- 有些浏览器不支持,如需支持要提供 polyfill
跨域请求解决
webpack 代理转发,简单配置如下:
在 webpack.dev.config.js 配置文件中找到 devServer 中的 proxy:
devServer: {
contentBase: path.resolve(__dirname, 'dist'),
historyApiFallback: true,
hot: true,
stats: {
chunks: false,
children: false,
},
// 增加一个key-value, key可为正在表达式, 重启服务后生效
proxy: {
'/v2/book/*': {
target: 'https://api.douban.com',
changeOrigin: true,
},
},
},
其他
如有书写测试性的代码,可以这样:
if(__DEV__) {
// 我是测试代码, 这样正式打包后会自动移除掉这部分代码
}
项目发布
在 deploy.js
填上七牛部署key
qiniu.conf.ACCESS_KEY = '';
qiniu.conf.SECRET_KEY = '';
提交代码
执行 npm version patch(修复 bug)/minor(功能小版本)/major(重要更新)
会在项目根目录下生成 dist,将 dist/index.html 交由后端渲染即可
可将 index.html 中静态资源修改成动态配置,以后前端资源更新,后端就无需发布重启了
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
上一篇: React 性能优化初探
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论