{"id":15043421,"url":"https://github.com/kenberkeley/react-demo","last_synced_at":"2025-05-15T13:08:28.726Z","repository":{"id":44384576,"uuid":"64744682","full_name":"kenberkeley/react-demo","owner":"kenberkeley","description":"React 示例项目 · 简易留言板。本项目拥有完善的文档说明与注释，让您快速上手 React 开发 SPA。Webpack / ES6 + Babel / Redux / React Router —— An Excellent React Starter，可能是东半球最佳的 React Starter，基于 Vue Cli 二次开发","archived":false,"fork":false,"pushed_at":"2023-04-24T08:26:40.000Z","size":633,"stargazers_count":1911,"open_issues_count":6,"forks_count":535,"subscribers_count":104,"default_branch":"master","last_synced_at":"2025-05-13T09:17:44.686Z","etag":null,"topics":["react","react-router","redux"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kenberkeley.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-08-02T09:44:32.000Z","updated_at":"2025-05-13T00:59:53.000Z","dependencies_parsed_at":"2024-09-25T01:49:57.918Z","dependency_job_id":"173f253d-343a-4969-a371-944d75ae1b57","html_url":"https://github.com/kenberkeley/react-demo","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kenberkeley%2Freact-demo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kenberkeley%2Freact-demo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kenberkeley%2Freact-demo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kenberkeley%2Freact-demo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kenberkeley","download_url":"https://codeload.github.com/kenberkeley/react-demo/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254346624,"owners_count":22055808,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["react","react-router","redux"],"created_at":"2024-09-24T20:49:00.030Z","updated_at":"2025-05-15T13:08:23.720Z","avatar_url":"https://github.com/kenberkeley.png","language":"JavaScript","readme":"# React 示例项目 · 简易留言板 + 待办事项\r\n\r\n\u003e ## *2017.7 升级版预览：[`react-scaffold`](https://github.com/kenberkeley/react-scaffold)，敬请期待！*\r\n\r\n![应用截图](./screenshot.png)\r\n\r\n\u003e ###写在前面  \r\n\u003e 一直以来，我都相当纳闷：为什么 React 的那些 starter kit 都构建得那么恶心？  \r\n\u003e 能不能像 [Vue Cli][vue-cli] 生成的[项目架构][vue-cli-template]般优雅？说干就干，本项目就改自 [Vue Demo][vue-demo]\r\n\u003e \r\n\u003e ### 更新\r\n\u003e 2016/8/28 \u0026nbsp; 引入 `cross-env` 解决跨平台问题，新增优化项 `DedupePlugin`  \r\n\u003e 2016/8/29 \u0026nbsp; 重命名 `makeContainer / makeReducer.js =\u003e createContainer / createReducer.js`  \r\n\u003e 2016/9/10 \u0026nbsp; 重构 `src/redux/`  \r\n\u003e 2016/10/15 \u0026nbsp; 同步 Vue Demo 的改动  \r\n\u003e 2016/10/16 \u0026nbsp; 改进：仅在开发模式下引入 React Hot Loader\r\n\r\n## 目录\r\n#### \u0026sect; [技术栈](#features)\r\n#### \u0026sect; [快速开始](#getting-started)\r\n  * [安装](#installation)\r\n  * [启动](#start)\r\n\r\n#### \u0026sect; [项目架构](#architecture)\r\n  * [目录结构](#tree)\r\n  * [特色](#character)\r\n\r\n#### \u0026sect; [开发](#development)\r\n  * [Webpack 配置](#webpack-configure)\r\n  * [规范](#standard)\r\n  * [性能](#performance)\r\n  \r\n#### \u0026sect; [测试](#testing)  \r\n#### \u0026sect; [部署](#deployment)\r\n#### \u0026sect; [参考](#reference)\r\n\r\n****\r\n\r\n## \u003ca name=\"features\"\u003e\u0026sect; 技术栈\u003c/a\u003e\r\n\u003e 详情可参阅 `package.json`\r\n\r\n* React 15.3.0\r\n* Redux\r\n* React Router\r\n* Ajax 请求库（Superagent / jQuery-Ajax / ...）\r\n* Webpack\r\n* ES6 + Babel\r\n* jQuery + BootStrap (UI)\r\n\r\n***\r\n\r\n## \u003ca name=\"getting-started\"\u003e\u0026sect; 快速开始\u003c/a\u003e\r\n在开始前，希望您已通读如下资料\r\n\r\n* [React 文档][react-doc]\r\n* [Redux 文档][redux-doc]（看完后懵逼的请转看 [Redux 莞式教程][simple-tutorial]）\r\n* [React Router 文档][react-router-doc]\r\n\r\n同时您还需要熟悉 ES6。例如，请把如下代码  \r\n`const foo = ({ hello: { world: bar } }) =\u003e ({ bar })`  \r\n转译成 ES5（答案请自行到 [Babel REPL][babel-repl] 在线编译验证）\r\n\r\n### \u003ca name=\"installation\"\u003e⊙ 安装\u003c/a\u003e\r\n\u003e 推荐升级到 node 5.x/6.x + npm 3.x 环境，**强烈推荐**使用 [`cnpm`](https://github.com/cnpm/cnpm) 安装依赖或手动   \r\n\u003e 切换到淘宝 npm 源：`npm set registry https://registry.npm.taobao.org/`  \r\n\u003e （经测试，`cnpm` 对于 `node-sass` 等问题多多的 Package 拥有秒杀能力）\r\n\r\n本示例项目需要结合 [简易留言板 RESTful API](https://github.com/kenberkeley/msg-board-api)  \r\n模拟前后端分离开发（还为了与 [Vue Demo][vue-demo] 共用）  \r\n请分别 `git clone`，打开**两个**命令窗口（ Windows 下推荐使用 `Cygwin / Git Bash`）**分别**切换到两者的目录下  \r\n分别敲下 `npm install` 安装依赖（为避免 Windows 下 npm 2.x 的软链接问题，可加上 `--no-bin-link` 完全解构所有依赖）\r\n\r\n### \u003ca name=\"start\"\u003e⊙ 启动\u003c/a\u003e\r\n先后在 `msg-board-api`、`react-demo` 的命令窗口下，敲下 `npm start`  \r\n如无意外，默认浏览器就会自动打开 `localhost:9090`，您立即可以看到效果  \r\n若浏览器没有自动弹出，则请自行手动访问  \r\n\r\n\u003e P.S. 如果您还不清楚如何安装与启动，请看这个 [issue][how-to-start]\r\n\r\n***\r\n\r\n## \u003ca name=\"architecture\"\u003e\u0026sect; 项目架构\u003c/a\u003e\r\n### \u003ca name=\"tree\"\u003e⊙ 目录结构\u003c/a\u003e\r\n```\r\n.\r\n├─ build/            # Webpack 配置目录\r\n├─ dist/             # build 生成的生产环境下的项目\r\n├─ src/              # 源码目录（开发都在这里进行）\r\n│   ├─ assets/         # 放置需要经由 Webpack 处理的静态文件\r\n│   ├─ components/     # 组件（COMPONENT）\r\n│   ├─ redux/          # Redux 一箩筐\r\n│   │   ├─ actions/      # （ACTION）\r\n│   │   ├─ reducers/     # （REDUCER）\r\n│   │   ├─ store/        # （STORE）\r\n│   ├── routes/        # 路由（ROUTE）\r\n│   ├── services/      # 服务（SERVICE，用于统一管理 XHR 请求，这是从 Vue Demo 中直接复制过来的）\r\n│   ├── utils/         # 工具库（UTIL）\r\n│   │   ├─ HoC/          # 高阶组件（HOC，全称 Higher Order Component）\r\n│   │   ├─ mixins/       # 混合（MIXIN）\r\n│   ├── views/         # 路由视图基页（VIEW）\r\n│   │   ├─ layout/       # 全局布局\r\n│   ├── app.js         # 启动文件\r\n│   ├── index.html     # 静态基页\r\n├── static/          # 放置无需经由 Webpack 处理的静态文件\r\n├── .babelrc         # Babel 转码配置\r\n├── .eslintignore    # （配置）ESLint 检查中需忽略的文件（夹）\r\n├── .eslintrc        # ESLint 配置\r\n├── .gitignore       # （配置）需被 Git 忽略的文件（夹）\r\n├── package.json     # （这个就不用多解释了吧）\r\n```\r\n\r\n在这里您可能会问：怎么没有 `containers/` 目录？  \r\n在本项目中，木偶组件与智能组件最大的差别在于：  \r\n前者的状态是通过父组件传入获得，而后者是直接**连接**到 `state` 获得  \r\n亦即：若一个木偶组件直接**连接**到 `state`，那么它就是一个所谓的智能组件  \r\n（详见 [`src/utils/createContainer.js`][createContainer] 中对 `react-redux` 的 [`connect`][connect] 函数的封装）  \r\n本示例项目唯一在组件的定义中自行使用 `connect` 函数的是 [`Navbar`][Navbar] 组件（且用到了 ES7 的装饰器）\r\n\r\n有关木偶组件与智能组件更为精确的论述，推荐 Redux 作者 Dan 的[这篇文章][dan-post]，避免教条主义\r\n\r\n\u003e 您可以根据业务需求改动目录结构。若目录使用频繁，建议配置 [路径别名](#alias)  \r\n\u003e 默认的路径别名见上面目录结构注释中大写形式的常量  \r\n\u003e **特别推荐：** 更新版本的 [Vue Demo 文档 · 目录结构](https://github.com/kenberkeley/vue-demo/blob/master/docs/zh-cn/Structure.md)\r\n\r\n### \u003ca name=\"character\"\u003e⊙ 特色\u003c/a\u003e\r\n* 本示例项目秉承最佳实践，**高度洁癖**地实现代码分离/复用\r\n* 优化目录结构，更好的模块分离，更接近 Vue 的开发模式\r\n* Redux DevTools，可选 [Chrome 插件形式][chrome-extension]（默认） 或 内嵌页面的[组件形式][devtools-component]\r\n* [Redux Logger][redux-logger] 打印动作及前后状态变化\r\n* [why-did-you-update][why-did-u-update] 检测不必要的组件重渲染（默认关闭）\r\n* 引入服务层统一管理 XHR 请求（好处请参考 Vue Demo 中的 [引入服务层][service-intro]）\r\n* 引入 [路径别名](#alias) 实现优雅的加载模式\r\n* 引入 [React Hot Reload][hot-loader]，支持热替换\r\n* 生产环境下的编译对代码进行[优化][react-optimize]\r\n* 迄今为止我见过的最完美的 starter kit\r\n\r\n\u003e 有关 Redux DevTools 与 why-did-you-update 的启用与禁用，见下面的 [开发环境全局变量](#dev-global-vars) 配置\r\n\r\n***\r\n\r\n## \u003ca name=\"development\"\u003e\u0026sect; 开发\u003c/a\u003e\r\n### \u003ca name=\"webpack-configure\"\u003e⊙ Webpack 配置\u003c/a\u003e\r\n\u003e 由于已经拥有相对成熟的 Webpack 配置，因此在一定程度上您可以不求甚解，但了解其配置会更能把握整体开发  \r\n\r\n* 前端开发服务器为 `localhost:9090`，可在 `build/webpack.dev.conf.js` 中找到\r\n\u003e 后端 RESTful API 基地址写在了 `src/services/xhr/config.js` 中，请根据实际自行修改\r\n\r\n* 框架 / 类库 须分离打包以加快开发时的编译速度并有利于缓存，详见 `build/webpack.base.conf.js` 中的 `vendor`\r\n\u003e 实际上该步骤可通过读取 `package.json` 的 `dependencies` 字段实现自动化，但其灵活度不够高，必要性也不大  \r\n\u003e P.S. 安装包时勿忘 `--save / --save-dev` 以添加依赖记录\r\n\r\n* \u003ca name=\"alias\"\u003e**路径别名**\u003c/a\u003e 的定义位于 `build/webpack.base.conf.js`，好处就是**引入与重构都很方便**\r\n\u003e 例如，在某组件中，引入 `userService` 需要 `import userService from '../../../services/userService'`  \r\n\u003e 但有了路径别名后，只需要 `import userService from 'SERVICE/userService'`  \r\n\u003e 相比于 AngularJS 中的依赖注入，这种方式依赖于构建工具，显得更为简单  \r\n\u003e \r\n\u003e 您可能会说，Webpack 只需要设定了 `root`属性为 `src/`  \r\n\u003e 就可以 `import userService from 'services/userService'`  \r\n\u003e 但在这里其实是会引起歧义的（不过这属于强迫症的范畴。。。）  \r\n\u003e 例如，`import createBrowserHistory from 'history/lib/createBrowserHistory'`  \r\n\u003e 您可能会觉得这是 `src/history/lib/createBrowserHistory.js`  \r\n\u003e 但实际上 [history][history] 是一个 npm package  \r\n\u003e 同样地，您又怎么知道 `services` 不是一个 npm package？  \r\n\u003e 而且重构之后，文件夹的变动会导致相对路径的变化，`services/` 目录未必仍在 `src/` 下    \r\n\u003e 因此，路径别名相当有必要。其**常量**的形式，让人一看就知道不是一个 npm package\r\n\r\n* 开发环境\u003ca name=\"dev-global-vars\"\u003e**全局变量**\u003c/a\u003e，由 `webpack.DefinePlugin` 提供（详见 `build/webpack.base.conf.js`）\r\n\u003e 默认有 `__DEV__` / `__PROD__` / `__COMPONENT_DEVTOOLS__` / `__WHY_DID_YOU_UPDATE__` 四个全局变量  \r\n\u003e 若要继续添加，则还需要在 `.eslintrc` 中 `globals` 同步写入\r\n\u003e \r\n\u003e 在此需要提醒，在 `package.json` 中设置 `NODE_ENV` 要注意末尾空格的[问题](http://stackoverflow.com/questions/11104028/#38948727)  \r\n\u003e 最好就是使用前 `trim` 一下：`process.env.NODE_ENV.trim()`\r\n\u003e \r\n\u003e 拓展阅读：[解读 UglifyJS](http://rapheal.sinaapp.com/tag/uglifyjs/)  \r\n\u003e 看看生产环境下编译 `if (__PROD__) { ... }` =\u003e `if (true) { ... }` 后 [UglifyJS](http://rapheal.sinaapp.com/2014/05/22/uglifyjs-squeeze/) 会如何处理\r\n\r\n\r\n### \u003ca name=\"standard\"\u003e⊙ 规范\u003c/a\u003e\r\n\u003e 本示例项目的代码极尽详细地添加了注释，其中不乏最佳实践提示\r\n\r\n为了减少代码量，我省去了 [Prop 验证][proptypes]，建议您在往后的开发中使用\r\n\r\n### \u003ca name=\"performance\"\u003e⊙ 性能\u003c/a\u003e\r\n大概可参阅如下文章：\r\n\r\n* React 文档 · [Advanced Performance](https://facebook.github.io/react/docs/advanced-performance.html)\r\n* 反鸡汤 · [Should I use shouldComponentUpdate](http://jamesknelson.com/should-i-use-shouldcomponentupdate/)（[译文](http://www.infoq.com/cn/news/2016/07/react-shouldComponentUpdate)）\r\n* 淘宝 FED · [高性能 React 组件](http://taobaofed.org/blog/2016/08/12/optimized-react-components/)\r\n* 腾讯 Dev Club · [React 移动 Web 极致优化](http://dev.qq.com/topic/579083d1c9da73584b02587d)\r\n\r\n***\r\n\r\n## \u003ca name=\"testing\"\u003e\u0026sect; 测试\u003c/a\u003e\r\n\u003e 请自行选择测试工具\r\n\r\n***\r\n\r\n## \u003ca name=\"deployment\"\u003e\u0026sect; 部署\u003c/a\u003e\r\n在 `react-demo` 的命令窗口下，敲下 `npm run build`，将会在项目根目录下生成 `dist/`  \r\n\u003e 您可以使用命令行静态资源服务器 [serve](https://github.com/tj/serve) ( `npm i serve -g` )，敲下 `serve dist/ -p [端口]` 来快速查看 build 后的项目  \r\n\u003e 还可以 `cd dist` 后，`python -m SimpleHTTPServer [端口]` 或 `php -S localhost:[端口]` 快速便捷地实现静态资源服务器\r\n\u003e\r\n\u003e 关于生产环境下的部署与优化，已超出本文档的论述范围，请自行查阅相关资料  \r\n\r\n***\r\n\r\n## \u003ca name=\"reference\"\u003e\u0026sect; 参考\u003c/a\u003e\r\n* [Vue Demo][vue-demo]\r\n* [davezuko/react-redux-starter-kit](https://github.com/davezuko/react-redux-starter-kit)\r\n* [探讨 React 项目目录结构](http://marmelab.com/blog/2015/12/17/react-directory-structure.html)\r\n\r\n[vue-cli]: https://github.com/vuejs/vue-cli\r\n[vue-cli-template]: http://vuejs-templates.github.io/webpack/structure\r\n[vue-demo]: https://github.com/kenberkeley/vue-demo\r\n[react-doc]: http://reactjs.cn/react/docs/getting-started-zh-CN.html\r\n[redux-doc]: http://camsong.github.io/redux-in-chinese/index.html\r\n[simple-tutorial]: https://github.com/kenberkeley/redux-simple-tutorial\r\n[react-router-doc]: http://react-guide.github.io/react-router-cn/\r\n[babel-repl]: http://babeljs.io/repl/\r\n[how-to-start]: https://github.com/kenberkeley/react-demo/issues/1\r\n[service-intro]: https://github.com/kenberkeley/vue-demo#service-layer\r\n[alias-intro]: https://github.com/kenberkeley/vue-demo#alias\r\n[createContainer]: https://github.com/kenberkeley/react-demo/blob/master/src/utils/createContainer.js\r\n[Navbar]: https://github.com/kenberkeley/react-demo/blob/master/src/components/Navbar/index.js\r\n[connect]: https://github.com/reactjs/react-redux/blob/master/docs/api.md#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options\r\n[dan-post]: https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0\r\n[chrome-extension]: https://github.com/zalmoxisus/redux-devtools-extension\r\n[devtools-component]: https://github.com/gaearon/redux-devtools\r\n[redux-logger]: https://github.com/evgenyrodionov/redux-logger\r\n[why-did-u-update]: https://github.com/garbles/why-did-you-update\r\n[hot-loader]: https://github.com/gaearon/react-hot-loader\r\n[react-optimize]: https://github.com/thejameskyle/babel-react-optimize\r\n[history]: https://github.com/ReactTraining/history\r\n[proptypes]: https://facebook.github.io/react/docs/reusable-components-zh-CN.html#prop-验证\r\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkenberkeley%2Freact-demo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkenberkeley%2Freact-demo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkenberkeley%2Freact-demo/lists"}