{"id":38794062,"url":"https://github.com/qingyang-id/react-antd-admin","last_synced_at":"2026-01-17T12:41:01.970Z","repository":{"id":42112242,"uuid":"109985819","full_name":"qingyang-id/react-antd-admin","owner":"qingyang-id","description":"react+antd+react-router4+saga+es6/es7","archived":false,"fork":false,"pushed_at":"2023-02-27T19:28:28.000Z","size":11029,"stargazers_count":15,"open_issues_count":22,"forks_count":5,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-05-27T12:15:04.951Z","etag":null,"topics":["antd","babel","babel7","es6","es7","jest","mocha","react","react-router","redux","redux-saga","saga","webpack","webpack4"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/qingyang-id.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-11-08T14:23:15.000Z","updated_at":"2022-11-23T06:47:27.000Z","dependencies_parsed_at":"2023-02-14T05:46:00.837Z","dependency_job_id":null,"html_url":"https://github.com/qingyang-id/react-antd-admin","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/qingyang-id/react-antd-admin","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qingyang-id%2Freact-antd-admin","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qingyang-id%2Freact-antd-admin/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qingyang-id%2Freact-antd-admin/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qingyang-id%2Freact-antd-admin/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/qingyang-id","download_url":"https://codeload.github.com/qingyang-id/react-antd-admin/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qingyang-id%2Freact-antd-admin/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28508523,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-17T11:50:55.898Z","status":"ssl_error","status_checked_at":"2026-01-17T11:50:55.569Z","response_time":85,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["antd","babel","babel7","es6","es7","jest","mocha","react","react-router","redux","redux-saga","saga","webpack","webpack4"],"created_at":"2026-01-17T12:40:59.049Z","updated_at":"2026-01-17T12:41:01.946Z","avatar_url":"https://github.com/qingyang-id.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# react-antd-admin(新版后台很快就与大家见面了)\n[![React Native](https://img.shields.io/badge/react-^16.x-brightgreen.svg?style=flat-square)](https://github.com/facebook/react)\n[![Redux](https://img.shields.io/badge/redux-^4.x-yellowgreen.svg?style=flat-square)](https://github.com/reactjs/redux)\n[![Redux Immutablejs](https://img.shields.io/badge/immutablejs-^0.0.8-orange.svg?style=flat-square)](https://github.com/indexiatech/redux-immutablejs)\n[![Ant Design](https://img.shields.io/badge/ant--design-^3.x-green.svg?style=flat-square)](https://github.com/ant-design/ant-design)\n[![Webpack](https://img.shields.io/badge/webpack-^4.x-blueviolet.svg?style=flat-square)](https://webpack.js.org/)\n[![Babel](https://img.shields.io/badge/babel-^7.x-important.svg?style=flat-square)](https://babeljs.io/)\n\n[![MIT](https://img.shields.io/dub/l/vibe-d.svg?style=flat-square)](http://opensource.org/licenses/MIT)\n\n\n## 最新更新\n\u003e  react版本升级到16，webpack版本升级4, babel升级到7，antd升级到3，同时引入Yarn缓存下载的每个包以及happypack利用了多进程，同时还利用缓存来使得rebuild 更快等\n\n\u003e  Redux使用调整\n\n\u003e 路由模式更改为浏览器模式\n\n## 前言\n\u003e  本工程主要基于react16 + redux + immutable + less + ES6/7 + webpack4 + babel7 + fetch + react-router + antd3实现的SPA后台管理系统模板。\n此项目是根据开源的项目升级改造而成。希望大家提供宝贵的意见和建议，谢谢。\n\n\u003e  如果觉得不错的话，请star一下吧 😊\n\n\u003e  邮\u0026emsp;\u0026emsp;\u0026ensp;箱： yqsailor@163.com\n\n### 下载\n\n```\n# git clone\n\ngit clone https://github.com/yqsailor/react-antd-admin.git\n\ncd react-antd-admin\n```\n\n### 安装\n```bash\n\n// 安装前请先确保已安装node和npm和yarn\nnpm install yarn -g\n\n// 安装成功后,再安装依赖，如果之前有用npm安装过，请先删掉node_modules\nyarn install\n```\n### 运行\n```bash\nyarn run start （开发版本，用于开发使用，热加载）\n\nyarn run build （发布生产版本，对代码进行混淆压缩，提取公共代码，分离css文件）\n```\n\n### 访问\n在浏览器地址栏输入[http://127.0.0.1:3601](http://127.0.0.1:3601)\n\n### 目标功能\n- [x] 登录页面\n- [x] 全站布局\n- [x] 全站路由\n- [ ] 对接接口，优化代码(冗余代码，不规则写法，界面样式)\n- [ ] 后台系统常用场景会逐个完善\n\n#### 历史更新\n\n  *2019.07.17*\n\n  \t1. webpack版本升级(webpack4)；\n\n  \t2. babel版本升级(babel7);\n\n  \t3. antd版本升级(antd3);\n  \t\n  \t4. react版本升级(react16);\n  \t\n  *2017.02.20*\n\n  \t1. 初始化项目目录;\n\n  \t2. webpack版本升级(webpack2.0)，并加上yarn，happypack等(最新迭代)；\n\n  \t3. 登录退出;\n\n  \t4. 整体布局;\n\n  \t5. 菜单映射路由(路由模式更改为浏览器模式);\n\n# 性能优化\n\n## 如何正确地在React中处理事件\n\n[参考官网](https://facebook.github.io/react/docs/handling-events.html)\n\n#### 1、构造器内绑定this\n```javascript\nclass MyComponent extends React.Component {\n    constructor(props) {\n        super(props);\n        this.state = {\n            count: 0\n        };\n        this.handleClick = this.handleClick.bind(this);\n    }\n\n    handleClick() {\n        this.setState({\n            count: ++this.state.count\n        });\n    }\n\n    render() {\n        return (\n        \u003cdiv\u003e\n            \u003cdiv\u003e{this.state.count}\u003c/div\u003e\n            \u003cbutton onClick={this.handleClick}\u003eClick\u003c/button\u003e\n        \u003c/div\u003e\n        );\n    }\n}\n```\n这种方式的好处是每次render，不会重新创建一个回调函数，没有额外的性能损失。需要注意的是，使用这种方式要在构造函数中为事件回调函数绑定this:  this.handleClick = this.handleClick.bind(this)，否则handleClick中的this是undefined。这是因为ES6 语法的缘故，ES6 的 Class 构造出来的对象上的方法默认不绑定到 this 上，需要我们手动绑定。\n\n#### 2、属性初始化\n使用ES7的 property initializers，代码可以这样写：\n```javascript\nclass MyComponent extends React.Component {\n    constructor(props) {\n        super(props);\n        this.state = {\n            count: 0\n        };\n    }\n\n    handleClick = () =\u003e {\n        this.setState({\n            count: ++this.state.count\n        });\n    }\n\n    render() {\n        return (\n        \u003cdiv\u003e\n            \u003cdiv\u003e{this.state.count}\u003c/div\u003e\n            \u003cbutton onClick={this.handleClick}\u003eClick\u003c/button\u003e\n        \u003c/div\u003e\n        );\n    }\n}\n```\n这种方式就不需要手动绑定this了。但是你需要知道，这个特性还处于试验阶段，默认是不支持的。如果你是使用官方脚手架Create React App 创建的应用，那么这个特性是默认支持的。你也可以自行在项目中引入babel的transform-class-properties插件获取这个特性支持。\n\n#### 3、箭头函数\n```javascript\nclass MyComponent extends React.Component {\n    render() {\n        return (\n        \u003cbutton onClick={()=\u003e{console.log('button clicked');}}\u003e\n            Click\n        \u003c/button\u003e\n        );\n    }\n}\n```\n当事件响应逻辑比较复杂时，如果再把所有的逻辑直接写在onClick的大括号内，就会导致render函数变得臃肿，不容易直观地看出组件render出的元素结构。这时，可以把逻辑封装成组件的一个方法，然后在箭头函数中调用这个方法。如下所示：\n```javascript\nclass MyComponent extends React.Component {\n    constructor(props) {\n        super(props);\n        this.state = {\n            count: 0\n        };\n    }\n    handleClick() {\n        this.setState({\n            count: ++this.state.count\n        });\n    }\n    render() {\n        return (\n        \u003cdiv\u003e\n            \u003cdiv\u003e{this.state.number}\u003c/div\u003e\n            \u003cbutton onClick={()=\u003e{this.handleClick();}}\u003eClick\u003c/button\u003e\n        \u003c/div\u003e\n        );\n    }\n}\n```\n这种方式最大的问题是，每次render调用时，都会重新创建一个事件的回调函数，带来额外的性能开销，当组件的层级越低时，这种开销就越大，因为任何一个上层组件的变化都可能会触发这个组件的render方法。当然，在大多数情况下，这点性能损失是可以不必在意的。这种方式也有一个好处，就是不需要考虑this的指向问题，因为这种写法保证箭头函数中的this指向的总是当前组件。\n\n#### 4、函数传递参数\n事件的回调函数默认是会被传入一个事件对象Event作为参数的。如果我想传入其他参数给回调函数应该怎么办呢？\n\n使用第一种方式（构造器内绑定this）的话，可以把绑定this的操作延迟到render中，在绑定this的同时，绑定额外的参数：\n```javascript\n// 代码6\nclass MyComponent extends React.Component {\n    constructor(props) {\n        super(props);\n        this.state = {\n        list: [1,2,3,4],\n        current: 1\n        };\n    }\n\n    handleClick(item) {\n        this.setState({\n            current: item\n        });\n    }\n\n    render() {\n        return (\n        \u003cul\u003e\n            {this.state.list.map(\n                (item)=\u003e(\n                \u003cli className={this.state.current === item ? 'current':''}\n                onClick={this.handleClick.bind(this, item)}\u003e{item}\n                \u003c/li\u003e\n                )\n            )}\n        \u003c/ul\u003e\n        );\n    }\n}\n```\n使用第二种方式（属性初始化），解决方案和第一种基本一致：\n```javascript\n// 代码7\nclass MyComponent extends React.Component {\n    constructor(props) {\n        super(props);\n        this.state = {\n            list: [1,2,3,4],\n            current: 1\n        };\n    }\n\n    handleClick = (item) =\u003e  {\n        this.setState({\n            current: item\n        });\n    }\n\n    render() {\n        return (\n        \u003cul\u003e\n            {this.state.list.map(\n                (item)=\u003e(\n                \u003cli className={this.state.current === item ? 'current':''}\n                onClick={this.handleClick.bind(undefined, item)}\u003e{item}\n                \u003c/li\u003e\n                )\n            )}\n        \u003c/ul\u003e\n        );\n    }\n}\n```\n不过这种方式就有点鸡肋了，因为虽然你不需要通过bind函数绑定this，但仍然要使用bind函数来绑定其他参数。\n\n使用第三种方式（函数传递参数）的话很简单，直接传就可以了：\n```javascript\nclass MyComponent extends React.Component {\n    constructor(props) {\n        super(props);\n        this.state = {\n            list: [1,2,3,4],\n            current: 1\n        };\n    }\n\n    handleClick(item,event) {\n        this.setState({\n            current: item\n        });\n    }\n\n    render() {\n        return (\n        \u003cul\u003e\n            {this.state.list.map(\n                (item)=\u003e(\n                \u003cli className={this.state.current === item ? 'current':''}\n                onClick={(event) =\u003e this.handleClick(item, event)}\u003e{item}\n                \u003c/li\u003e\n                )\n            )}\n        \u003c/ul\u003e\n        );\n    }\n}\n```\n\n关于事件响应的回调函数，还有一个地方需要注意。不管你在回调函数中有没有显式的声明事件参数Event，React都会把事件Event作为参数传递给回调函数，且参数Event的位置总是在其他自定义参数的后面。例如，在代码6和代码7中，handleClick的参数中虽然没有声明Event参数，但你依然可以通过arguments[1]获取到事件Event对象。\n\n总结一下，三种绑定事件回调的方式，第一种有额外的性能损失；第二种需要手动绑定this，代码量增多；第三种用到了ES7的特性，目前并非默认支持，需要Babel插件的支持，但是写法最为简洁，也不需要手动绑定this。推荐使用第二种和第三种方式。\n\n## Immutable 详解及 React 中实践 (https://github.com/camsong/blog/issues/3)\n\n## react 实现pure render的时候，bind(this)隐患\n```javascript\nexport default class Parent extends Component {\n...\n  render() {\n    const {name,age} =this.state;\n    return (\n      \u003cdiv\u003e\n        \u003cChild name={name} age={age} onClick={this._handleClick.bind(this)}\u003e\u003c/Child\u003e//bug 所在\n      \u003c/div\u003e\n    )\n  }\n...\n}\n```\n发现一个问题，对于Child这个子组件来说，在父组件re－render的时候，即使Child得前后两个props都没改变，它依旧会re－render。。即使用immutable.js也不好使。。。原来啊，父组件每次render，_handleClick都会执行bind(this) 这样_handleClick的引用每次都会改。。所以Child前后两次props其实是不一样的。。\n那怎么办？把bind（this）去掉？不行 还必须得用。真正的答案是 让父组件每次render 不执行bind（this），直接提前在constructor执行好，修改之后\n```javascript\nexport default class Parent extends Component {\n  constructor(props){\n    super(props)\n    this._handleClick=this._handleClick.bind(this)//改成这样\n  }\n  render() {\n    const {name,age} =this.state;\n    return (\n      \u003cdiv\u003e\n        \u003cChild name={name} age={age} onClick={this._handleClick}\u003e\u003c/Child\u003e\n      \u003c/div\u003e\n    )\n  }\n...\n}\n```\n## 子组件跟随父组件re－render\n想象一下这种场景，一个父组件下面一大堆子组件。然后呢，这个父组件re－render。是不是下面的子组件都得跟着re－render。可是很多子组件里面是冤枉的啊！！很多子组件的props 和 state 然而并没有改变啊！！虽然virtual dom 的diff 算法很快。。但是性能也不是这么浪费的啊！！\n```javascript\nclass Child  extends Component {\n  render() {\n    console.log(\"我re-render了\");\n    const {name,age} = this.props;\n\n      return (\n        \u003cdiv\u003e\n          \u003cspan\u003e姓名:\u003c/span\u003e\n          \u003cspan\u003e{name}\u003c/span\u003e\n          \u003cspan\u003e age:\u003c/span\u003e\n          \u003cspan\u003e{age}\u003c/span\u003e\n        \u003c/div\u003e\n      )\n  }\n}\nconst Person = pureRender(Child);\n```\npureRender其实就是一个函数，接受一个Component。把这个Component搞一搞，返回一个Component看他pureRender的源代码就一目了然\n```javascript\nfunction shouldComponentUpdate(nextProps, nextState) {\n  return shallowCompare(this, nextProps, nextState);\n}\n\nfunction pureRende(component) {\n  component.prototype.shouldComponentUpdate = shouldComponentUpdate;\n}\nmodule.exports = pureRender;\n```\npureRender很简单，就是把传进来的component的shouldComponentUpdate给重写掉了，原来的shouldComponentUpdate，无论怎样都是return ture，现在不了，我要用shallowCompare比一比，shallowCompare代码及其简单，如下\n```javascript\nfunction shallowCompare(instance, nextProps, nextState) {\n  return !shallowEqual(instance.props, nextProps) || !shallowEqual(instance.state, nextState);\n}\n```\n一目了然。分别拿现在props\u0026state和要传进来的props\u0026state，用shallowEqual比一比，要是props\u0026state都一样的话，就return false\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fqingyang-id%2Freact-antd-admin","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fqingyang-id%2Freact-antd-admin","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fqingyang-id%2Freact-antd-admin/lists"}