可能是东半球最好的 React + Redux 启动器,基于 Vue Cli 二次开发

React 示例项目 · 简易留言板 + 待办事项(Github 地址

写在前面

一直以来,我都相当纳闷:为什么 React 的那些 starter kit 都构建得那么恶心?
能不能像 Vue Cli 生成的项目架构般优雅?说干就干,本项目就改自 Vue Demo

§ 技术栈

详情可参阅 package.json

  • React 15.3.0

  • Redux

  • React Router

  • Ajax 请求库(Superagent / jQuery-Ajax / ...)

  • Webpack

  • ES6 + Babel

  • jQuery + BootStrap (UI)

§ 快速开始

在开始前,希望您已通读如下资料

同时您还需要熟悉 ES6。例如,请把如下代码
const foo = ({ hello: { world: bar } }) => ({ bar })
转译成 ES5(答案请自行到 Babel REPL 在线编译验证)

⊙ 安装

建议升级到 node 5.x/6.x + npm 3.x 环境
推荐使用 cnpm 或手动切换到淘宝 npm 源
npm set registry https://registry.npm.taobao.org/

本示例项目需要结合 简易留言板 RESTful API
模拟前后端分离开发(还为了与 Vue Demo 共用)
请分别 git clone,打开两个命令窗口( Windows 下推荐使用 Cygwin分别切换到两者的目录下
分别敲下 npm install 安装依赖(为避免 Windows 下的 npm 软链接问题,可加上 --no-bin-link 完全解构所有依赖)

虽然我们已经切换到了淘宝 npm 源,但安装 node-sass@3.8.0 的时候还是很有可能卡住
因为它的安装需要从 Github 的 AWS 服务器拉取二进制文件,因此您可以为它指定源:
npm i node-sass@3.8.0 --registry=https://registry.npm.taobao.org

如果您想简单粗暴一点,这里还提供了 node_modules.zip,直接解压即可

⊙ 启动

先后在 msg-board-apireact-demo 的命令窗口下,敲下 npm start
如无意外,默认浏览器就会自动打开 localhost:9090,您立即可以看到效果
若浏览器没有自动弹出,则请自行手动访问

开发过程中,通过 Webpack 处理的静态资源都由基于内存的 webpack-dev-server 提供
P.S. 如果您还不清楚如何安装与启动,请看这个 issue

§ 项目架构

⊙ 目录结构

.
├─ build/            # Webpack 配置目录
├─ dist/             # build 生成的生产环境下的项目
├─ src/              # 源码目录(开发都在这里进行)
│   ├─ components/     # 组件(COMPONENT)
│   ├─ redux/          # Redux 一箩筐
│   │   ├─ actions/      # (ACTION)
│   │   ├─ reducers/     # (REDUCER)
│   │   ├─ store/        # (STORE)
│   ├── routes/        # 路由(ROUTE)
│   ├── services/      # 服务(SERVICE,用于统一管理 XHR 请求,这是从 Vue Demo 中直接复制过来的)
│   ├── utils/         # 工具库(UTIL)
│   │   ├─ HoC/          # 高阶组件(HOC,全称 Higher Order Component)
│   │   ├─ mixins/       # 混合(MIXIN)
│   ├── views/         # 路由视图基页(VIEW)
│   │   ├─ layout/       # 全局布局
│   ├── app.js         # 启动文件
│   ├── index.html     # 静态基页
├── static/          # 放置无需经由 Webpack 处理的静态文件
├── .babelrc         # Babel 转码配置
├── .eslintignore    # (配置)ESLint 检查中需忽略的文件(夹)
├── .eslintrc        # ESLint 配置
├── .gitignore       # (配置)需被 Git 忽略的文件(夹)
├── package.json     # (这个就不用多解释了吧)

在这里您可能会问:怎么没有 containers/ 目录?
在我的理解里,木偶组件与智能组件最大的差别在于:
前者的状态是通过父组件传入获得,而后者是直接连接state 获得
亦即:若一个木偶组件直接连接state,那么它就是一个所谓的智能组件
(详见 src/utils/makeContainer.js 中对 react-reduxconnect 函数的封装)
本示例项目唯一在组件的定义中自行使用 connect 函数的是 Navbar 组件(且用到了 ES7 的装饰器)

您可以根据业务需求改动目录结构。若目录使用频繁,建议配置 路径别名
默认的路径别名见上面目录结构注释中大写形式的常量

⊙ 特色

  • 本示例项目秉承最佳实践,高度洁癖地实现代码分离/复用

  • 优化目录结构,更好的模块分离,更接近 Vue 的开发模式

  • Redux DevTools,可选 Chrome 插件形式(默认) 或 内嵌页面的组件形式

  • Redux Logger 打印动作及前后状态变化

  • why-did-you-update 检测不必要的组件重渲染(默认关闭)

  • 引入服务层统一管理 XHR 请求(好处请参考 Vue Demo 中的 引入服务层

  • 引入 路径别名 实现优雅的加载模式

  • 引入 React Hot Reload,支持热替换

  • 生产环境下的编译对代码进行优化

  • 迄今为止我见过的最完美的 starter kit

有关 Redux DevTools 与 why-did-you-update 的启用与禁用,见下面的 开发环境全局变量 配置

§ 开发

⊙ Webpack 配置

由于已经拥有相对成熟的 Webpack 配置,因此在一定程度上您可以不求甚解,但了解其配置会更能把握整体开发

  • 前端开发服务器为 localhost:9090,可在 build/webpack.config.dev.js 中找到

后端 RESTful API 基地址写在了 src/services/xhr/config.js 中,请根据实际自行修改

  • 框架 / 类库 须分离打包以加快开发时的编译速度并有利于缓存,详见 build/webpack.base.conf.js 中的 vendor

  • 路径别名 的定义位于 build/webpack.base.conf.js,好处就是引入与重构都很方便

例如,在某组件中,引入 userService 需要 import userService from '../../../services/userService'
但有了路径别名后,只需要 import userService from 'SERVICE/userService'
相比于 AngularJS 中的依赖注入,这种方式依赖于构建工具,显得更为简单

您可能会说,Webpack 只需要设定了 root属性为 src/
就可以 import userService from 'services/userService'
但在这里其实是会引起歧义的(不过这属于强迫症的范畴。。。)
例如,import createBrowserHistory from 'history/lib/createBrowserHistory'
您可能会觉得这是 src/history/lib/createBrowserHistory.js
但实际上 history 是一个 npm package
同样地,您又怎么知道 services 不是一个 npm package?
而且重构之后,文件夹的变动会导致相对路径的变化,services/ 目录未必仍在 src/
因此,路径别名相当有必要。其常量的形式,让人一看就知道不是一个 npm package

  • 开发环境全局变量,由 webpack.DefinePlugin 提供(详见 build/webpack.base.conf.js

默认有 __DEV__ / __PROD__ / __COMPONENT_DEVTOOLS__ / __WHY_DID_YOU_UPDATE__ 四个全局变量
若要继续添加,则还需要在 .eslintrcglobals 同步写入

在此需要提醒,在 package.json 中设置 NODE_ENV 要注意末尾空格的问题
最好就是使用前 trim 一下:process.env.NODE_ENV.trim()

拓展阅读:解读 UglifyJS
看看生产环境下编译 if (__PROD__) { ... } => if (true) { ... }UglifyJS 会如何处理

⊙ 规范

本示例项目的代码极尽详细地添加了注释,其中不乏最佳实践提示

为了减少代码量,我省去了 Prop 验证,建议您在往后的开发中使用

§ 测试

请自行选择测试工具

§ 部署

react-demo 的命令窗口下,敲下 npm run build,将会在项目根目录下生成 dist/

您可以使用命令行静态资源服务器 serve ( npm i serve -g ),敲下 serve -p [端口] dist 来快速查看 build 后的项目
还可以 cd dist 后,python -m SimpleHTTPServer [端口]php -S localhost:[端口] 快速便捷地实现静态资源服务器

关于生产环境下的部署与优化,已超出本文档的论述范围,请自行查阅相关资料
在这里您可能需要全局安装 rimrafnpm i rimraf -g(或根据指引配置环境变量避免全局安装)

§ 参考

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


react 中的高阶组件主要是对于 hooks 之前的类组件来说的,如果组件之中有复用的代码,需要重新创建一个父类,父类中存储公共代码,返回子类,同时把公用属性...
我们上一节了解了组件的更新机制,但是只是停留在表层上,例如我们的 setState 函数式同步执行的,我们的事件处理直接绑定在了 dom 元素上,这些都跟 re...
我们上一节了解了 react 的虚拟 dom 的格式,如何把虚拟 dom 转为真实 dom 进行挂载。其实函数是组件和类组件也是在这个基础上包裹了一层,一个是调...
react 本身提供了克隆组件的方法,但是平时开发中可能很少使用,可能是不了解。我公司的项目就没有使用,但是在很多三方库中都有使用。本小节我们来学习下如果使用该...
mobx 是一个简单可扩展的状态管理库,中文官网链接。小编在接触 react 就一直使用 mobx 库,上手简单不复杂。
我们在平常的开发中不可避免的会有很多列表渲染逻辑,在 pc 端可以使用分页进行渲染数限制,在移动端可以使用下拉加载更多。但是对于大量的列表渲染,特别像有实时数据...
本小节开始前,我们先答复下一个同学的问题。上一小节发布后,有小伙伴后台来信问到:‘小编你只讲了类组件中怎么使用 ref,那在函数式组件中怎么使用呢?’。确实我们...
上一小节我们了解了固定高度的滚动列表实现,因为是固定高度所以容器总高度和每个元素的 size、offset 很容易得到,这种场景也适合我们常见的大部分场景,例如...
上一小节我们处理了 setState 的批量更新机制,但是我们有两个遗漏点,一个是源码中的 setState 可以传入函数,同时 setState 可以传入第二...
我们知道 react 进行页面渲染或者刷新的时候,会从根节点到子节点全部执行一遍,即使子组件中没有状态的改变,也会执行。这就造成了性能不必要的浪费。之前我们了解...
在平时工作中的某些场景下,你可能想在整个组件树中传递数据,但却不想手动地通过 props 属性在每一层传递属性,contextAPI 应用而生。
楼主最近入职新单位了,恰好新单位使用的技术栈是 react,因为之前一直进行的是 vue2/vue3 和小程序开发,对于这些技术栈实现机制也有一些了解,最少面试...
我们上一节了了解了函数式组件和类组件的处理方式,本质就是处理基于 babel 处理后的 type 类型,最后还是要处理虚拟 dom。本小节我们学习下组件的更新机...
前面几节我们学习了解了 react 的渲染机制和生命周期,本节我们正式进入基本面试必考的核心地带 -- diff 算法,了解如何优化和复用 dom 操作的,还有...
我们在之前已经学习过 react 生命周期,但是在 16 版本中 will 类的生命周期进行了废除,虽然依然可以用,但是需要加上 UNSAFE 开头,表示是不安...
上一小节我们学习了 react 中类组件的优化方式,对于 hooks 为主流的函数式编程,react 也提供了优化方式 memo 方法,本小节我们来了解下它的用...
开源不易,感谢你的支持,❤ star me if you like concent ^_^
hel-micro,模块联邦sdk化,免构建、热更新、工具链无关的微模块方案 ,欢迎关注与了解
本文主题围绕concent的setup和react的五把钩子来展开,既然提到了setup就离不开composition api这个关键词,准确的说setup是由...
ReactsetState的执行是异步还是同步官方文档是这么说的setState()doesnotalwaysimmediatelyupdatethecomponent.Itmaybatchordefertheupdateuntillater.Thismakesreadingthis.staterightaftercallingsetState()apotentialpitfall.Instead,usecom