{"id":4115,"date":"2025-03-07T10:07:58","date_gmt":"2025-03-07T02:07:58","guid":{"rendered":"https:\/\/feizhaojun.com\/?p=4115"},"modified":"2025-03-07T11:16:09","modified_gmt":"2025-03-07T03:16:09","slug":"%e4%bb%a5ant-design-pro%e4%b8%ba%e4%be%8b%e8%af%a6%e8%a7%a3redux%e3%80%81redux-saga%e3%80%81dva","status":"publish","type":"post","link":"https:\/\/feizhaojun.com\/?p=4115","title":{"rendered":"\u4ee5Ant Design Pro\u4e3a\u4f8b\u8be6\u89e3Redux\u3001redux-saga\u3001dva"},"content":{"rendered":"<p>\u539f\u6587\u94fe\u63a5\uff1a<a href=\"https:\/\/www.cnblogs.com\/colorful-coco\/p\/9454315.html\">https:\/\/www.cnblogs.com\/colorful-coco\/p\/9454315.html<\/a><\/p>\n<p>Ant Design Pro \u662f\u4e00\u4e2a\u4f01\u4e1a\u7ea7\u4e2d\u540e\u53f0\u524d\u7aef\/\u8bbe\u8ba1\u89e3\u51b3\u65b9\u6848\u3002\u672c\u5730\u73af\u5883\u9700\u8981\u5b89\u88c5 node \u548c git\uff0c\u6280\u672f\u6808\u57fa\u4e8e ES2015+\u3001React\u3001dva\u3001g2 \u548c antd\u3002<\/p>\n<p>\u53c2\u8003\uff1a<\/p>\n<ul>\n<li><a href=\"https:\/\/dvajs.com\/\">https:\/\/dvajs.com\/<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/ant-design\/ant-design-pro\/blob\/master\/README.zh-CN.md\">https:\/\/github.com\/ant-design\/ant-design-pro\/blob\/master\/README.zh-CN.md<\/a><\/li>\n<li><a href=\"https:\/\/pro.ant.design\/docs\/getting-started-cn\">https:\/\/pro.ant.design\/docs\/getting-started-cn<\/a><\/li>\n<\/ul>\n<h2>1 \u9884\u5907\u77e5\u8bc6<\/h2>\n<h3>1.1 Redux<\/h3>\n<p>Redux \u662f JavaScript \u72b6\u6001\u5bb9\u5668\uff0c\u63d0\u4f9b\u53ef\u9884\u6d4b\u5316\u7684\u72b6\u6001\u7ba1\u7406\u3002Redux \u9664\u4e86\u548c React \u4e00\u8d77\u7528\u5916\uff0c\u8fd8\u652f\u6301\u5176\u5b83\u754c\u9762\u5e93\u3002<\/p>\n<h4>1.1.1 connect()<\/h4>\n<p>connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])<\/p>\n<p>\u8fde\u63a5 React \u7ec4\u4ef6\u4e0e Redux store\u3002<\/p>\n<p>[mapStateToProps(state, [ownProps]): stateProps](Function)<\/p>\n<p>\u5982\u679c\u5b9a\u4e49\u8be5\u53c2\u6570\uff0c\u7ec4\u4ef6\u5c06\u4f1a\u76d1\u542c Redux store \u7684\u53d8\u5316\u3002\u53ea\u8981 Redux store \u53d1\u751f\u6539\u53d8\uff0c<code>mapStateToProps<\/code> \u51fd\u6570\u5c31\u4f1a\u88ab\u8c03\u7528\uff0c\u8be5\u56de\u8c03\u51fd\u6570\u5fc5\u987b\u8fd4\u56de\u4e00\u4e2a\u7eaf\u5bf9\u8c61\uff0c\u8fd9\u4e2a\u5bf9\u8c61\u4f1a\u4e0e\u7ec4\u4ef6\u7684 props \u5408\u5e76\u3002<\/p>\n<ul>\n<li>\u51fd\u6570\u5c06\u88ab\u8c03\u7528\u4e24\u6b21\u3002\u7b2c\u4e00\u6b21\u662f\u8bbe\u7f6e\u53c2\u6570\uff0c\u7b2c\u4e8c\u6b21\u662f\u7ec4\u4ef6\u4e0e Redux store \u8fde\u63a5\uff1a<code>connect(mapStateToProps, mapDispatchToProps, mergeProps)(MyComponent)<\/code>\u3002<\/li>\n<li>connect \u51fd\u6570\u4e0d\u4f1a\u4fee\u6539\u4f20\u5165\u7684 React \u7ec4\u4ef6\uff0c\u8fd4\u56de\u7684\u662f\u4e00\u4e2a\u65b0\u7684\u5df2\u4e0e Redux store \u8fde\u63a5\u7684\u7ec4\u4ef6\uff0c\u800c\u4e14\u4f60\u5e94\u8be5\u4f7f\u7528\u8fd9\u4e2a\u65b0\u7ec4\u4ef6\u3002<\/li>\n<li><code>mapStateToProps<\/code> \u51fd\u6570\u63a5\u6536\u6574\u4e2a Redux store \u7684 state \u4f5c\u4e3a props\uff0c\u7136\u540e\u8fd4\u56de\u4e00\u4e2a\u4f20\u5165\u5230\u7ec4\u4ef6 props \u7684\u5bf9\u8c61\u3002<\/li>\n<\/ul>\n<p>\u6ce8\u5165 <code>dispatch<\/code> \u548c <code>todos<\/code>\uff1a<\/p>\n<pre><code class=\"language-javascript\">function mapStateToProps(state) {\n  return { todos: state.todos }\n}\nexport default connect(mapStateToProps)(TodoApp)\n\n\/\/ \u6ce8\u5165 dispatch \u548c\u5168\u5c40 state\nexport default connect(state =&gt; state)(TodoApp)\n\/\/ \u4e0d\u8981\u8fd9\u6837\u505a\uff01\u8fd9\u4f1a\u5bfc\u81f4\u6bcf\u6b21 action \u90fd\u89e6\u53d1\u6574\u4e2a TodoApp \u91cd\u65b0\u6e32\u67d3\n\/\/ \u6700\u597d\u5728\u591a\u4e2a\u7ec4\u4ef6\u4e0a\u4f7f\u7528 connect()\uff0c\u6bcf\u4e2a\u7ec4\u4ef6\u53ea\u76d1\u542c\u5b83\u6240\u5173\u8054\u7684\u90e8\u5206 state\u3002<\/code><\/pre>\n<h4>1.1.2 Action<\/h4>\n<p>Action \u662f\u628a\u6570\u636e\u4ece\u5e94\u7528\uff08\u8fd9\u91cc\u4e4b\u6240\u4ee5\u4e0d\u53eb view \u662f\u56e0\u4e3a\u8fd9\u4e9b\u6570\u636e\u6709\u53ef\u80fd\u662f\u670d\u52a1\u5668\u54cd\u5e94\uff0c\u7528\u6237\u8f93\u5165\u6216\u5176\u5b83\u975e view \u7684\u6570\u636e \uff09\u4f20\u5230 store \u7684\u6709\u6548\u8f7d\u8377\u3002\u5b83\u662f store \u6570\u636e\u7684\u552f\u4e00\u6765\u6e90\u3002\u4e00\u822c\u6765\u8bf4\u4f60\u4f1a\u901a\u8fc7 <code>store.dispatch()<\/code> \u5c06 action \u4f20\u5230 store\u3002<\/p>\n<p>Action \u672c\u8d28\u4e0a\u662f JavaScript \u666e\u901a\u5bf9\u8c61\u3002\u6211\u4eec\u7ea6\u5b9a\uff0caction \u5185\u5fc5\u987b\u4f7f\u7528\u4e00\u4e2a\u5b57\u7b26\u4e32\u7c7b\u578b\u7684 <code>type<\/code> \u5b57\u6bb5\u6765\u8868\u793a\u5c06\u8981\u6267\u884c\u7684\u52a8\u4f5c\u3002<\/p>\n<h3>1.2 redux-saga<\/h3>\n<p>redux-saga \u662f\u4e00\u4e2a redux \u4e2d\u95f4\u4ef6\uff0c\u610f\u5473\u7740\u8fd9\u4e2a\u7ebf\u7a0b\u53ef\u4ee5\u901a\u8fc7\u6b63\u5e38\u7684 redux action \u4ece\u4e3b\u5e94\u7528\u7a0b\u5e8f\u542f\u52a8\uff0c\u6682\u505c\u548c\u53d6\u6d88\uff0c\u5b83\u80fd\u8bbf\u95ee\u5b8c\u6574\u7684 redux state\uff0c\u4e5f\u53ef\u4ee5 dispatch redux action\u3002<\/p>\n<p>redux-saga \u4f7f\u7528\u4e86 ES6 \u7684 Generator \u529f\u80fd\uff0c\u8ba9\u5f02\u6b65\u7684\u6d41\u7a0b\u66f4\u6613\u4e8e\u8bfb\u53d6\uff0c\u5199\u5165\u548c\u6d4b\u8bd5\u3002\u901a\u8fc7\u8fd9\u6837\u7684\u65b9\u5f0f\uff0c\u8fd9\u4e9b\u5f02\u6b65\u7684\u6d41\u7a0b\u770b\u8d77\u6765\u5c31\u50cf\u662f\u6807\u51c6\u540c\u6b65\u7684 Javascript \u4ee3\u7801\u3002<\/p>\n<pre><code class=\"language-javascript\">effects: {\n  *create({ payload: values }, { call, put }) {\n    yield call(usersService.create, values);\n    yield put({ type: &#039;reload&#039; });\n  },\n  *reload(action, { put, select }) {\n    const page = yield select(state =&gt; state.users.page);\n    yield put({ type: &#039;fetch&#039;, payload: { page } });\n  },\n}<\/code><\/pre>\n<h4>1.2.1 call(fn, ...args)<\/h4>\n<p>\u521b\u5efa\u4e00\u4e2a Effect \u63cf\u8ff0\u4fe1\u606f\uff0c\u7528\u6765\u547d\u4ee4 middleware \u4ee5\u53c2\u6570 <code>args<\/code> \u8c03\u7528\u51fd\u6570 <code>fn<\/code> \u3002<\/p>\n<ul>\n<li>fn: Function\uff1a\u4e00\u4e2a Generator \u51fd\u6570, \u4e5f\u53ef\u4ee5\u662f\u4e00\u4e2a\u8fd4\u56de Promise \u6216\u4efb\u610f\u5176\u5b83\u503c\u7684\u666e\u901a\u51fd\u6570\u3002<\/li>\n<li>args: Array&lt;any&gt;\uff1a\u4f20\u9012\u7ed9 <code>fn<\/code> \u7684\u53c2\u6570\u6570\u7ec4\u3002<\/li>\n<\/ul>\n<h4>1.2.2 put(action)<\/h4>\n<p>\u521b\u5efa\u4e00\u4e2a Effect \u63cf\u8ff0\u4fe1\u606f\uff0c\u7528\u6765\u547d\u4ee4 middleware \u5411 Store \u53d1\u8d77\u4e00\u4e2a action\u3002 \u8fd9\u4e2a effect \u662f\u975e\u963b\u585e\u578b\u7684\uff0c\u5e76\u4e14\u6240\u6709\u5411\u4e0b\u6e38\u629b\u51fa\u7684\u9519\u8bef\uff08\u4f8b\u5982\u5728 reducer \u4e2d\uff09\uff0c\u90fd\u4e0d\u4f1a\u5192\u6ce1\u56de\u5230 saga \u5f53\u4e2d\u3002<\/p>\n<h4>1.2.3 select(selector, ...args)<\/h4>\n<p>\u521b\u5efa\u4e00\u4e2a Effect\uff0c\u7528\u6765\u547d\u4ee4 middleware \u5728\u5f53\u524d Store \u7684 state \u4e0a\u8c03\u7528\u6307\u5b9a\u7684\u9009\u62e9\u5668\u3002<\/p>\n<ul>\n<li><code>selector: Function<\/code>\uff1a\u4e00\u4e2a <code>(state, ...args) =&gt; args<\/code> \u7684\u51fd\u6570\u3002\u5b83\u63a5\u53d7\u5f53\u524d state \u548c\u4e00\u4e9b\u53ef\u9009\u53c2\u6570\uff0c\u5e76\u8fd4\u56de\u5f53\u524d Store state \u4e0a\u7684\u4e00\u90e8\u5206\u6570\u636e\u3002<\/li>\n<\/ul>\n<h2>2 dva<\/h2>\n<p>dva \u9996\u5148\u662f\u4e00\u4e2a\u57fa\u4e8e redux \u548c redux-saga \u7684\u6570\u636e\u6d41\u65b9\u6848\uff0c\u7136\u540e\u4e3a\u4e86\u7b80\u5316\u5f00\u53d1\u4f53\u9a8c\uff0cdva \u8fd8\u989d\u5916\u5185\u7f6e\u4e86 react-router \u548c fetch\uff0c\u6240\u4ee5\u4e5f\u53ef\u4ee5\u7406\u89e3\u4e3a\u4e00\u4e2a\u8f7b\u91cf\u7ea7\u7684\u5e94\u7528\u6846\u67b6\u3002<\/p>\n<p>dva \u662f\u57fa\u4e8e\u73b0\u6709\u5e94\u7528\u67b6\u6784 (redux + react-router + redux-saga \u7b49)\u7684\u4e00\u5c42\u8f7b\u91cf\u5c01\u88c5\uff0c\u6ca1\u6709\u5f15\u5165\u4efb\u4f55\u65b0\u6982\u5ff5\u3002dva \u5e2e\u4f60\u81ea\u52a8\u5316\u4e86Redux \u67b6\u6784\u4e00\u4e9b\u7e41\u7410\u7684\u6b65\u9aa4\uff0c\u6bd4\u5982redux store \u7684\u521b\u5efa\uff0c\u4e2d\u95f4\u4ef6\u7684\u914d\u7f6e\uff0c\u8def\u7531\u7684\u521d\u59cb\u5316\u7b49\u7b49\uff0c\u53ea\u9700\u5199\u51e0\u884c\u4ee3\u7801\u5c31\u53ef\u4ee5\u5b9e\u73b0\u4e0a\u8ff0\u6b65\u9aa4\u3002 <\/p>\n<h3>2.1 \u4f7f\u7528 antd<\/h3>\n<p>\u901a\u8fc7 npm \u5b89\u88c5 <code>antd<\/code> \u548c <code>babel-plugin-import<\/code>\u3002<code>babel-plugin-import<\/code> \u662f\u7528\u6765\u6309\u9700\u52a0\u8f7d antd \u7684\u811a\u672c\u548c\u6837\u5f0f\u7684\u3002\u7f16\u8f91 <code>.webpackrc<\/code>\uff0c\u4f7f <code>babel-plugin-import<\/code> \u63d2\u4ef6\u751f\u6548\u3002<\/p>\n<pre><code class=\"language-javascript\">\/\/ .webpackrc.js\nextraBabelPlugins: [[&#039;import&#039;, { libraryName: &#039;antd&#039;, libraryDirectory: &#039;es&#039;, style: true }]]<\/code><\/pre>\n<h3>2.2 dva \u5e94\u7528<\/h3>\n<pre><code class=\"language-javascript\">\/\/ src\/index.js \u5165\u53e3js\nimport dva from &#039;dva&#039;;\nimport browserHistory from &#039;history\/createBrowserHistory&#039;;\nimport createLoading from &#039;dva-loading&#039;;\n\n\/\/ 1. Initialize\nconst app = dva({\n    history: browserHistory(),\n});\n\/\/ 2. Plugins\napp.use(createLoading());\n\/\/ 3. Model\napp.model(require(&#039;.\/models\/global&#039;).default);\napp.model(require(&#039;.\/models\/menu&#039;).default);\n\/\/ 4. Router\napp.router(require(&#039;.\/router&#039;).default);\n\/\/ 5. Start\napp.start(&#039;#root&#039;); \/\/ \u542f\u52a8\u5e94\u7528<\/code><\/pre>\n<p><code>dva(opts)<\/code> \u521b\u5efa\u5e94\u7528\uff0c\u8fd4\u56de dva \u5b9e\u4f8b\u3002\uff08\u6ce8\uff1adva \u652f\u6301\u591a\u5b9e\u4f8b\uff09<\/p>\n<p><code>opts<\/code> \u5305\u542b\uff1a<\/p>\n<ul>\n<li><code>history<\/code>\uff1a\u6307\u5b9a\u7ed9\u8def\u7531\u7528\u7684 history\uff0c\u9ed8\u8ba4\u662f <code>hashHistory<\/code><\/li>\n<\/ul>\n<h3>2.3 \u5b9a\u4e49\u8def\u7531<\/h3>\n<p>app.router(({ history, app }) =&gt; RouterConfig)<\/p>\n<p>\u6ce8\u518c\u8def\u7531\u8868\uff0c\u63a8\u8350\u628a\u8def\u7531\u4fe1\u606f\u62bd\u6210\u4e00\u4e2a\u5355\u72ec\u7684\u6587\u4ef6\uff0c\u8fd9\u6837\u7ed3\u5408 babel-plugin-dva-hmr \u53ef\u5b9e\u73b0\u8def\u7531\u548c\u7ec4\u4ef6\u7684\u70ed\u52a0\u8f7d\uff08\u53ea\u66f4\u65b0\u9875\u9762\u4fee\u6539\u7684\u90e8\u5206\uff0c\u4e0d\u4f1a\u5237\u65b0\u6574\u4e2a\u9875\u9762\uff09\u3002<\/p>\n<pre><code class=\"language-javascript\">\/\/ .webpackrc.js\nenv: {\n  development: {\n    extraBabelPlugins: [&#039;dva-hmr&#039;],\n  },\n},<\/code><\/pre>\n<h3>2.4 \u5b9a\u4e49 Model\uff08\u5904\u7406\u6570\u636e\u548c\u903b\u8f91\uff09<\/h3>\n<p>dva \u901a\u8fc7 model \u7684\u6982\u5ff5\u628a\u4e00\u4e2a\u9886\u57df\u7684\u6a21\u578b\u7ba1\u7406\u8d77\u6765\uff0c\u5305\u542b\u540c\u6b65\u66f4\u65b0 state \u7684 reducers\uff0c\u5904\u7406\u5f02\u6b65\u903b\u8f91\u7684 effects\uff0c\u8ba2\u9605\u6570\u636e\u6e90\u7684 subscriptions \u3002<\/p>\n<pre><code class=\"language-javascript\">import * as usersService from &#039;..\/services\/users&#039;;\n\nexport default {\n  namespace: &#039;users&#039;,\n  state: {\n    list: [],\n    total: null,\n    page: null,\n  },\n  reducers: {\n    save(state, { payload: { data: list, total, page } }) {\n      return { ...state, list, total, page };\n    },\n  },\n  effects: {\n    *fetch({ payload: { page = 1 } }, { call, put }) {\n      const { data, headers } = yield call(usersService.fetch, { page });\n      yield put({\n        type: &#039;save&#039;,\n        payload: {\n          data,\n          total: parseInt(headers[&#039;x-total-count&#039;], 10),\n          page: parseInt(page, 10),\n        },\n      });\n    },\n    *remove({ payload: id }, { call, put }) {\n      yield call(usersService.remove, id);\n      yield put({ type: &#039;reload&#039; });\n    },*reload(action, { put, select }) {\n      const page = yield select(state =&gt; state.users.page);\n      yield put({ type: &#039;fetch&#039;, payload: { page } });\n    },\n  },\n  subscriptions: {\n    setup({ dispatch, history }) {\n      return history.listen(({ pathname, query }) =&gt; {\n        if (pathname === &#039;\/users&#039;) {\n          dispatch({ type: &#039;fetch&#039;, payload: query });\n        }\n      });\n    },\n  },\n};<\/code><\/pre>\n<p><code>namespace<\/code>\uff1amodel \u7684\u547d\u540d\u7a7a\u95f4\uff0c\u540c\u65f6\u4e5f\u662f\u4ed6\u5728\u5168\u5c40 state \u4e0a\u7684\u5c5e\u6027<\/p>\n<p><code>state<\/code>\uff1a\u521d\u59cb\u503c<\/p>\n<p><code>reducers<\/code>\uff1a\u4ee5 key\/value \u683c\u5f0f\u5b9a\u4e49 reducer\u3002\u7528\u4e8e\u5904\u7406\u540c\u6b65\u64cd\u4f5c\uff0c\u552f\u4e00\u53ef\u4ee5\u4fee\u6539 <code>state<\/code> \u7684\u5730\u65b9\u3002\u7531 <code>action<\/code> \u89e6\u53d1<\/p>\n<p><code>effects<\/code>\uff1a\u4ee5 key\/value \u683c\u5f0f\u5b9a\u4e49 effect\u3002\u7528\u4e8e\u5904\u7406\u5f02\u6b65\u64cd\u4f5c\u548c\u4e1a\u52a1\u903b\u8f91\uff0c\u4e0d\u76f4\u63a5\u4fee\u6539 <code>state<\/code>\u3002\u7531 <code>action<\/code> \u89e6\u53d1\uff0c\u53ef\u4ee5\u89e6\u53d1 <code>action<\/code>\uff0c\u53ef\u4ee5\u548c\u670d\u52a1\u5668\u4ea4\u4e92\uff0c\u53ef\u4ee5\u83b7\u53d6\u5168\u5c40 <code>state<\/code> \u7684\u6570\u636e\u7b49\u7b49\u3002<\/p>\n<p><code>subscriptions<\/code>\uff1a\u4ee5 key\/value \u683c\u5f0f\u5b9a\u4e49 subscription\u3002subscription \u662f\u8ba2\u9605\uff0c\u7528\u4e8e\u8ba2\u9605\u4e00\u4e2a\u6570\u636e\u6e90\uff0c\u7136\u540e\u6839\u636e\u9700\u8981 dispatch \u76f8\u5e94\u7684 action\u3002\u5728 <code>app.start()<\/code> \u65f6\u88ab\u6267\u884c\uff0c\u6570\u636e\u6e90\u53ef\u4ee5\u662f\u5f53\u524d\u7684\u65f6\u95f4\u3001\u670d\u52a1\u5668\u7684 websocket \u8fde\u63a5\u3001keyboard \u8f93\u5165\u3001geolocation \u53d8\u5316\u3001history \u8def\u7531\u53d8\u5316\u7b49\u7b49\u3002<\/p>\n<p><code>app.model(model)<\/code>\uff1a\u6ce8\u518c model<\/p>\n<h3>2.5 \u7f16\u5199UI\uff1aComponent \u5e76 connect \u8d77\u6765<\/h3>\n<pre><code class=\"language-javascript\">import React from &#039;react&#039;;\nimport { connect } from &#039;dva&#039;;\nimport { Table, Pagination, Popconfirm, Button } from &#039;antd&#039;;\nimport { routerRedux } from &#039;dva\/router&#039;;\nimport styles from &#039;.\/Users.css&#039;;\nimport { PAGE_SIZE } from &#039;..\/..\/..\/..\/constants&#039;;\nimport UserModal from &#039;.\/UserModal&#039;;\n\nfunction Users({ dispatch, list: dataSource, loading, total, page: current }) {\n  function deleteHandler(id) {\n    dispatch({\n      type: &#039;users\/remove&#039;,\n      payload: id,\n    });\n  }\n\n  function pageChangeHandler(page) {\n    dispatch(\n      routerRedux.push({\n        pathname: &#039;\/users&#039;,\n        query: { page },\n      })\n    );\n  }\n\n  const columns = [\n    {\n      title: &#039;Username&#039;,\n      dataIndex: &#039;username&#039;,\n      key: &#039;username&#039;,\n      render: text =&gt; &lt;a href=&quot;&quot;&gt;{text}&lt;\/a&gt;,\n    },\n    {\n      title: &#039;Street&#039;,\n      dataIndex: &#039;address.street&#039;,\n      key: &#039;street&#039;,\n    },\n    {\n      title: &#039;Website&#039;,\n      dataIndex: &#039;website&#039;,\n      key: &#039;website&#039;,\n    },\n    {\n      title: &#039;Operation&#039;,\n      key: &#039;operation&#039;,\n      render: (text, record) =&gt; (\n        &lt;span className={styles.operation}&gt;\n          &lt;Popconfirm title=&quot;Confirm to delete?&quot; onConfirm={deleteHandler.bind(null, record.id)}&gt;\n            &lt;a href=&quot;&quot;&gt;Delete&lt;\/a&gt;\n          &lt;\/Popconfirm&gt;\n        &lt;\/span&gt;\n      ),\n    },\n  ];\n\n  return (\n    &lt;div className={styles.normal}&gt;\n      &lt;div&gt;\n        &lt;Table\n          columns={columns}\n          dataSource={dataSource}\n          loading={loading}\n          rowKey={record =&gt; record.id}\n          pagination={false}\n        \/&gt;\n        &lt;Pagination\n          className=&quot;ant-table-pagination&quot;\n          total={total}\n          current={current}\n          pageSize={PAGE_SIZE}\n          onChange={pageChangeHandler}\n        \/&gt;\n      &lt;\/div&gt;\n    &lt;\/div&gt;\n  );\n}\n\nfunction mapStateToProps(state) {\n  const { list, total, page } = state.users;\n  return {\n    loading: state.loading.models.users,\n    list,\n    total,\n    page,\n  };\n}\n\nexport default connect(mapStateToProps)(Users);<\/code><\/pre>\n<h3>2.6 \u76f8\u5173\u6982\u5ff5<\/h3>\n<p><strong>dva \u63d0\u4f9b\u4e86 connect \u65b9\u6cd5<\/strong><\/p>\n<p>\u8fd9\u4e2a connect \u5c31\u662f react-redux \u7684 connect \u3002 connect \u65b9\u6cd5\u8fd4\u56de\u7684\u4e5f\u662f\u4e00\u4e2a React \u7ec4\u4ef6\uff0c\u901a\u5e38\u79f0\u4e3a\u5bb9\u5668\u7ec4\u4ef6\u3002\u56e0\u4e3a\u5b83\u662f\u539f\u59cb UI \u7ec4\u4ef6\u7684\u5bb9\u5668\uff0c\u5373\u5728\u5916\u9762\u5305\u4e86\u4e00\u5c42 State\u3002connect \u65b9\u6cd5\u4f20\u5165\u7684\u7b2c\u4e00\u4e2a\u53c2\u6570\u662f mapStateToProps \u51fd\u6570\uff0cmapStateToProps \u51fd\u6570\u4f1a\u8fd4\u56de\u4e00\u4e2a\u5bf9\u8c61\uff0c\u7528\u4e8e\u5efa\u7acb State \u5230 Props \u7684\u6620\u5c04\u5173\u7cfb\u3002<\/p>\n<p>\u6570\u636e\u7684\u6539\u53d8\u53d1\u751f\u901a\u5e38\u662f\u901a\u8fc7\u7528\u6237\u4ea4\u4e92\u884c\u4e3a\u6216\u8005\u6d4f\u89c8\u5668\u884c\u4e3a\uff08\u5982\u8def\u7531\u8df3\u8f6c\u7b49\uff09\u89e6\u53d1\u7684\uff0c\u5f53\u6b64\u7c7b\u884c\u4e3a\u4f1a\u6539\u53d8\u6570\u636e\u7684\u65f6\u5019\u53ef\u4ee5\u901a\u8fc7 <code>dispatch<\/code> \u53d1\u8d77\u4e00\u4e2a action\uff0c\u5982\u679c\u662f\u540c\u6b65\u884c\u4e3a\u4f1a\u76f4\u63a5\u901a\u8fc7 <code>Reducers<\/code> \u6539\u53d8 <code>State<\/code> \uff0c\u5982\u679c\u662f\u5f02\u6b65\u884c\u4e3a\uff08\u526f\u4f5c\u7528\uff09\u4f1a\u5148\u89e6\u53d1 <code>Effects<\/code> \u7136\u540e\u6d41\u5411 <code>Reducers<\/code> \u6700\u7ec8\u6539\u53d8 <code>State<\/code>\u3002<\/p>\n<p><strong>Model \u5bf9\u8c61\u7684\u5c5e\u6027<\/strong><\/p>\n<ul>\n<li>namespace: \u5f53\u524d Model \u7684\u540d\u79f0\u3002\u6574\u4e2a\u5e94\u7528\u7684 State\uff0c\u7531\u591a\u4e2a\u5c0f\u7684 Model \u7684 State \u4ee5 namespace \u4e3a key \u5408\u6210<\/li>\n<li>state: \u8be5 Model \u5f53\u524d\u7684\u72b6\u6001\u3002\u6570\u636e\u4fdd\u5b58\u5728\u8fd9\u91cc\uff0c\u76f4\u63a5\u51b3\u5b9a\u4e86\u89c6\u56fe\u5c42\u7684\u8f93\u51fa<\/li>\n<li>reducers: Action \u5904\u7406\u5668\uff0c\u5904\u7406\u540c\u6b65\u52a8\u4f5c\uff0c\u7528\u6765\u7b97\u51fa\u6700\u65b0\u7684 State<\/li>\n<li>effects\uff1aAction \u5904\u7406\u5668\uff0c\u5904\u7406\u5f02\u6b65\u52a8\u4f5c<\/li>\n<\/ul>\n<p><strong>Action \u662f\u4e00\u4e2a\u666e\u901a javascript \u5bf9\u8c61<\/strong><\/p>\n<p>\u5b83\u662f\u6539\u53d8 State \u7684\u552f\u4e00\u9014\u5f84\u3002\u65e0\u8bba\u662f\u4ece UI \u4e8b\u4ef6\u3001\u7f51\u7edc\u56de\u8c03\uff0c\u8fd8\u662f WebSocket \u7b49\u6570\u636e\u6e90\u6240\u83b7\u5f97\u7684\u6570\u636e\uff0c\u6700\u7ec8\u90fd\u4f1a\u901a\u8fc7 dispatch \u51fd\u6570\u8c03\u7528\u4e00\u4e2a action\uff0c\u4ece\u800c\u6539\u53d8\u5bf9\u5e94\u7684\u6570\u636e\u3002action \u5fc5\u987b\u5e26\u6709 <code>type<\/code> \u5c5e\u6027\u6307\u660e\u5177\u4f53\u7684\u884c\u4e3a\uff0c\u5176\u5b83\u5b57\u6bb5\u53ef\u4ee5\u81ea\u5b9a\u4e49\uff0c\u5982\u679c\u8981\u53d1\u8d77\u4e00\u4e2a action \u9700\u8981\u4f7f\u7528 <code>dispatch<\/code> \u51fd\u6570\uff1b\u9700\u8981\u6ce8\u610f\u7684\u662f <code>dispatch<\/code> \u662f\u5728\u7ec4\u4ef6 connect Models\u4ee5\u540e\uff0c\u901a\u8fc7 props \u4f20\u5165\u7684\u3002\u5728 dva \u4e2d\uff0cconnect Model \u7684\u7ec4\u4ef6\u901a\u8fc7 props \u53ef\u4ee5\u8bbf\u95ee\u5230 dispatch\uff0c\u53ef\u4ee5\u8c03\u7528 Model \u4e2d\u7684 Reducer \u6216\u8005 Effects\u3002<\/p>\n<pre><code class=\"language-javascript\">dispatch({\n  type: &#039;user\/add&#039;, \/\/ \u5982\u679c\u5728 model \u5916\u8c03\u7528\uff0c\u9700\u8981\u6dfb\u52a0 namespace\n  payload: {}, \/\/ \u9700\u8981\u4f20\u9012\u7684\u4fe1\u606f\n});<\/code><\/pre>\n<p><strong>Reducer\u51fd\u6570\u63a5\u53d7\u4e24\u4e2a\u53c2\u6570<\/strong><\/p>\n<p>\u4e4b\u524d\u5df2\u7ecf\u7d2f\u79ef\u8fd0\u7b97\u7684\u7ed3\u679c\u548c\u5f53\u524d\u8981\u88ab\u7d2f\u79ef\u7684\u503c\uff0c\u8fd4\u56de\u7684\u662f\u4e00\u4e2a\u65b0\u7684\u7d2f\u79ef\u7ed3\u679c\u3002\u5728 dva \u4e2d\uff0creducers \u805a\u5408\u79ef\u7d2f\u7684\u7ed3\u679c\u662f\u5f53\u524d model \u7684 state \u5bf9\u8c61\u3002\u901a\u8fc7 actions \u4e2d\u4f20\u5165\u7684\u503c\uff0c\u4e0e\u5f53\u524d reducers \u4e2d\u7684\u503c\u8fdb\u884c\u8fd0\u7b97\u83b7\u5f97\u65b0\u7684\u503c\uff08\u4e5f\u5c31\u662f\u65b0\u7684 state\uff09\u3002<\/p>\n<pre><code>state: {\n  list: [],\n  total: null,\n  page: null,\n},\nreducers: {\n  save(state, { payload: { data: list, total, page } }) {\n    return { ...state, list, total, page };\n  },\n}<\/code><\/pre>\n<p><strong>Effect<\/strong><\/p>\n<p>Action \u5904\u7406\u5668\uff0c\u5904\u7406\u5f02\u6b65\u52a8\u4f5c\uff0c\u57fa\u4e8e Redux-saga \u5b9e\u73b0\u3002Effect \u6307\u7684\u662f\u526f\u4f5c\u7528\u3002\u6839\u636e\u51fd\u6570\u5f0f\u7f16\u7a0b\uff0c\u8ba1\u7b97\u4ee5\u5916\u7684\u64cd\u4f5c\u90fd\u5c5e\u4e8e Effect\uff0c\u5178\u578b\u7684\u5c31\u662f I\/O \u64cd\u4f5c\u3001\u6570\u636e\u5e93\u8bfb\u5199\u3002<\/p>\n<p>dva \u63d0\u4f9b\u591a\u4e2a effect \u51fd\u6570\u5185\u90e8\u7684\u5904\u7406\u51fd\u6570\uff0c\u6bd4\u8f83\u5e38\u7528\u7684\u662f <code>call<\/code> \u548c <code>put<\/code>\u3002<\/p>\n<ul>\n<li>call\uff1a\u6267\u884c\u5f02\u6b65\u51fd\u6570<\/li>\n<li>put\uff1a\u53d1\u51fa\u4e00\u4e2a Action\uff0c\u7c7b\u4f3c\u4e8e dispatch<\/li>\n<\/ul>\n<pre><code>effects: {\n  *create({ payload: values }, { call, put }) {\n    yield call(usersService.create, values);\n    yield put({ type: &#039;reload&#039; });\n  },\n  *reload(action, { put, select }) {\n    const page = yield select(state =&gt; state.users.page);\n    yield put({ type: &#039;fetch&#039;, payload: { page } });\n  },\n}<\/code><\/pre>\n<p><strong>Router<\/strong><\/p>\n<p>\u8fd9\u91cc\u7684\u8def\u7531\u901a\u5e38\u6307\u7684\u662f\u524d\u7aef\u8def\u7531\uff0c\u7531\u4e8e\u6211\u4eec\u7684\u5e94\u7528\u73b0\u5728\u901a\u5e38\u662f\u5355\u9875\u5e94\u7528\uff0c\u6240\u4ee5\u9700\u8981\u524d\u7aef\u4ee3\u7801\u6765\u63a7\u5236\u8def\u7531\u903b\u8f91\uff0c\u901a\u8fc7\u6d4f\u89c8\u5668\u63d0\u4f9b\u7684 History API \u53ef\u4ee5\u76d1\u542c\u6d4f\u89c8\u5668url\u7684\u53d8\u5316\uff0c\u4ece\u800c\u63a7\u5236\u8def\u7531\u76f8\u5173\u64cd\u4f5c\u3002<\/p>\n<p>dva \u5b9e\u4f8b\u63d0\u4f9b\u4e86 router \u65b9\u6cd5\u6765\u63a7\u5236\u8def\u7531\uff0c\u4f7f\u7528\u7684\u662freact-router\u3002<\/p>\n<p>\u5728\u7ec4\u4ef6\u8bbe\u8ba1\u65b9\u6cd5\u4e2d\uff0c\u6211\u4eec\u63d0\u5230\u8fc7 Container Components\uff0c\u5728 dva \u4e2d\u6211\u4eec\u901a\u5e38\u5c06\u5176\u7ea6\u675f\u4e3a Route Components\uff0c\u56e0\u4e3a\u5728 dva \u4e2d\u6211\u4eec\u901a\u5e38\u4ee5\u9875\u9762\u7ef4\u5ea6\u6765\u8bbe\u8ba1 Container Components\u3002<\/p>\n<p>\u6240\u4ee5\u5728 dva \u4e2d\uff0c\u901a\u5e38\u9700\u8981 connect Model\u7684\u7ec4\u4ef6\u90fd\u662f Route Components\uff0c\u7ec4\u7ec7\u5728 <code>\/routes\/<\/code> \u76ee\u5f55\u4e0b\uff0c\u800c <code>\/components\/<\/code> \u76ee\u5f55\u4e0b\u5219\u662f\u7eaf\u7ec4\u4ef6\u3002<\/p>\n<p><strong>\u7ec4\u4ef6\u8bbe\u8ba1<\/strong><\/p>\n<p>React \u5e94\u7528\u662f\u7531\u4e00\u4e2a\u4e2a\u72ec\u7acb\u7684 Component \u7ec4\u6210\u7684\uff0c\u6211\u4eec\u5728\u62c6\u5206 Component \u7684\u8fc7\u7a0b\u4e2d\u8981\u5c3d\u91cf\u8ba9\u6bcf\u4e2a Component \u4e13\u6ce8\u505a\u81ea\u5df1\u7684\u4e8b\u3002<\/p>\n<p>\u4e00\u822c\u6765\u8bf4\uff0c\u6211\u4eec\u7684\u7ec4\u4ef6\u6709\u4e24\u79cd\u8bbe\u8ba1\uff1aContainer Component\u3001Presentational Component<\/p>\n<p><a href=\"https:\/\/github.com\/dvajs\/dva-docs\/blob\/master\/v1\/zh-cn\/tutorial\/04-%E7%BB%84%E4%BB%B6%E8%AE%BE%E8%AE%A1%E6%96%B9%E6%B3%95.md#container-component\">Container Component<\/a><\/p>\n<p>Container Component \u4e00\u822c\u6307\u7684\u662f\u5177\u6709<code>\u76d1\u542c\u6570\u636e\u884c\u4e3a<\/code>\u7684\u7ec4\u4ef6\uff0c\u4e00\u822c\u6765\u8bf4\u5b83\u4eec\u7684\u804c\u8d23\u662f<code>\u7ed1\u5b9a\u76f8\u5173\u8054\u7684 model \u6570\u636e<\/code>\uff0c\u4ee5\u6570\u636e\u5bb9\u5668\u7684\u89d2\u8272\u5305\u542b\u5176\u5b83\u5b50\u7ec4\u4ef6\u3002<\/p>\n<p>Presentational Component<\/p>\n<p>\u5b83\u4e0d\u4f1a\u5173\u8054\u8ba2\u9605 model \u4e0a\u7684\u6570\u636e\uff0c\u800c\u6240\u9700\u6570\u636e\u7684\u4f20\u9012\u5219\u662f\u901a\u8fc7 props \u4f20\u9012\u5230\u7ec4\u4ef6\u5185\u90e8\u3002<\/p>\n<p>\u5bf9\u7ec4\u4ef6\u5206\u7c7b\uff0c\u4e3b\u8981\u6709\u4e24\u4e2a\u597d\u5904\uff1a\u8ba9\u9879\u76ee\u7684\u6570\u636e\u5904\u7406\u66f4\u52a0\u96c6\u4e2d\uff1b\u8ba9\u7ec4\u4ef6\u9ad8\u5185\u805a\u4f4e\u8026\u5408\uff0c\u66f4\u52a0\u805a\u7126\uff1b<\/p>\n<p>\u8bd5\u60f3\u5982\u679c\u6bcf\u4e2a\u7ec4\u4ef6\u90fd\u53bb\u8ba2\u9605\u6570\u636e model\uff0c\u90a3\u4e48\u4e00\u65b9\u9762\u7ec4\u4ef6\u672c\u8eab\u8ddf model \u8026\u5408\u592a\u591a\uff0c\u53e6\u4e00\u65b9\u9762\u4ee3\u7801\u8fc7\u4e8e\u96f6\u6563\uff0c\u5230\u5904\u90fd\u5728\u64cd\u4f5c\u6570\u636e\uff0c\u4f1a\u5e26\u6765\u540e\u671f\u7ef4\u62a4\u7684\u70e6\u607c\u3002<\/p>\n<p>\u9664\u4e86\u5199\u6cd5\u4e0a\u8ba2\u9605\u6570\u636e\u7684\u533a\u522b\u4ee5\u5916\uff0c\u5728\u8bbe\u8ba1\u601d\u8def\u4e0a\u4e24\u4e2a\u7ec4\u4ef6\u4e5f\u6709\u5f88\u5927\u4e0d\u540c\u3002 <code>Presentational Component<\/code>\u662f\u72ec\u7acb\u7684\u7eaf\u7cb9\u7684\uff0c\u53ef\u4ee5\u53c2\u8003 ant.design UI\u7ec4\u4ef6\u7684React\u5b9e\u73b0 \uff0c\u6bcf\u4e2a\u7ec4\u4ef6\u8ddf\u4e1a\u52a1\u6570\u636e\u5e76\u6ca1\u6709\u8026\u5408\u5173\u7cfb\uff0c\u53ea\u662f\u5b8c\u6210\u81ea\u5df1\u72ec\u7acb\u7684\u4efb\u52a1\uff0c\u9700\u8981\u7684\u6570\u636e\u901a\u8fc7 <code>props<\/code> \u4f20\u9012\u8fdb\u6765\uff0c\u9700\u8981\u64cd\u4f5c\u7684\u884c\u4e3a\u901a\u8fc7\u63a5\u53e3\u66b4\u9732\u51fa\u53bb\u3002 \u800c <code>Container Component<\/code> \u66f4\u50cf\u662f\u72b6\u6001\u7ba1\u7406\u5668\uff0c\u5b83\u8868\u73b0\u4e3a\u4e00\u4e2a\u5bb9\u5668\uff0c\u8ba2\u9605\u5b50\u7ec4\u4ef6\u9700\u8981\u7684\u6570\u636e\uff0c\u7ec4\u7ec7\u5b50\u7ec4\u4ef6\u7684\u4ea4\u4e92\u903b\u8f91\u548c\u5c55\u793a\u3002<\/p>\n<h2>3 \u5176\u5b83<\/h2>\n<h3>3.1 roadhog<\/h3>\n<p>roadhog \u662f\u548c webpack \u76f8\u4f3c\u7684\u5e93\uff0c\u8d77\u7684\u662f webpack \u81ea\u52a8\u6253\u5305\u548c\u70ed\u66f4\u66ff\u7684\u4f5c\u7528<\/p>\n<p>roadhog \u662f\u4e00\u4e2a cli \u5de5\u5177\uff0c\u63d0\u4f9b <code>dev<\/code>\u3001 <code>build<\/code> \u548c <code>test<\/code> \u4e09\u4e2a\u547d\u4ee4\uff0c\u5206\u522b\u7528\u4e8e\u672c\u5730\u8c03\u8bd5\u3001\u6784\u5efa\u548c\u6d4b\u8bd5\uff0c\u5e76\u4e14\u63d0\u4f9b\u4e86\u7279\u522b\u6613\u7528\u7684 mock \u529f\u80fd\u3002\u5728\u4f53\u9a8c\u4e0a\uff0c\u4fdd\u6301\u4e86\u548c create-react-app\u4e00\u81f4\uff08\u5982 redbox \u663e\u793a\u51fa\u9519\u4fe1\u606f\u3001HMR\u3001ESLint \u51fa\u9519\u63d0\u793a\u7b49\u7b49\uff09\uff0c\u5e76\u4e14\u63d0\u4f9b\u4e86 JSON \u683c\u5f0f\u7684\u914d\u7f6e\u65b9\u5f0f\u3002\u5982\u679c create-react-app \u7684\u9ed8\u8ba4\u914d\u7f6e\u4e0d\u80fd\u6ee1\u8db3\u9700\u6c42\uff0c\u800c\u4ed6\u53c8\u4e0d\u63d0\u4f9b\u5b9a\u5236\u7684\u529f\u80fd\uff0c\u4e8e\u662f\u57fa\u4e8e\u4ed6\u5b9e\u73b0\u4e86\u4e00\u4e2a\u53ef\u914d\u7f6e\u7248\u3002\u6240\u4ee5\u5982\u679c\u65e2\u8981 create-react-app \u7684\u4f18\u96c5\u4f53\u9a8c\uff0c\u53c8\u60f3\u5b9a\u5236\u914d\u7f6e\uff0c\u90a3\u4e48\u53ef\u4ee5\u8bd5\u8bd5 roadhog\u3002<\/p>\n<pre><code class=\"language-shell\">## Install globally or locally \n$ npm i roadhog -g\n\n## Local development \n$ roadhog dev\n\n## Build \n$ roadhog build\n\n## Test \n$ roadhog test<\/code><\/pre>\n<p>roadhog dev \u652f\u6301 mock, \u5728<code>.roadhogrc.mock.js<\/code> \u91cc\u914d\u7f6e<\/p>\n<pre><code class=\"language-javascript\">export default {\n  \/\/ Support type as Object and Array\n  &#039;GET \/api\/users&#039;: { users: [1,2] },\n  \/\/ Method like GET or POST can be omitted\uff08\u7701\u7565\uff09\n  &#039;\/api\/users\/1&#039;: { id: 1 },\n  \/\/ Support for custom functions, the API is the same as express@4\n  &#039;POST \/api\/users\/create&#039;: (req, res) =&gt; { res.end(&#039;OK&#039;); },\n};<\/code><\/pre>\n<p>roadhog \u7684 webpack \u90e8\u5206\u662f\u57fa\u4e8e af-webpack \u7684\u5b9e\u73b0\u3002\u5728\u9879\u76ee\u6839\u76ee\u5f55\u521b\u5efa <code>.webpackrc<\/code> \u8fdb\u884c\u914d\u7f6e\uff0c\u683c\u5f0f\u662f JSON\u3002<\/p>\n<h3>3.2 react-router-redux \u548c dva<\/h3>\n<p>redux \u662f\u72b6\u6001\u7ba1\u7406\u7684\u5e93\uff0crouter \u662f(\u552f\u4e00)\u63a7\u5236\u9875\u9762\u8df3\u8f6c\u7684\u5e93\u3002\u4e24\u8005\u90fd\u5f88\u7f8e\u597d\uff0c\u4f46\u662f\u4e0d\u7f8e\u597d\u7684\u662f\u4e24\u8005\u65e0\u6cd5\u534f\u540c\u5de5\u4f5c\u3002\u6362\u53e5\u8bdd\u8bf4\uff0c\u5f53\u8def\u7531\u53d8\u5316\u4ee5\u540e\uff0cstore \u65e0\u6cd5\u611f\u77e5\u5230\u3002\u4e8e\u662f\u4fbf\u6709\u4e86 <code>react-router-redux<\/code>\u3002<\/p>\n<p><code>react-router-redux<\/code> \u662f redux \u7684\u4e00\u4e2a\u4e2d\u95f4\u4ef6\uff0c\u4e3b\u8981\u4f5c\u7528\u662f\uff1a\u52a0\u5f3a\u4e86React Router\u5e93\u4e2dhistory\u8fd9\u4e2a\u5b9e\u4f8b\uff0c\u4ee5\u5141\u8bb8\u5c06history\u4e2d\u63a5\u53d7\u5230\u7684\u53d8\u5316\u53cd\u5e94\u5230state\u4e2d\u53bb\u3002<\/p>\n<p>\u4ece\u4ee3\u7801\u4e0a\u8bb2\uff0c\u4e3b\u8981\u662f\u76d1\u542c\u4e86 history \u7684\u53d8\u5316\u3002dva \u5728\u6b64\u57fa\u7840\u4e0a\u53c8\u8fdb\u884c\u4e86\u4e00\u5c42\u4ee3\u7406\uff0c\u628a\u4ee3\u7406\u540e\u7684\u5bf9\u8c61\u5f53\u4f5c\u521d\u59cb\u503c\u4f20\u9012\u7ed9\u4e86 dva-core\uff0c\u65b9\u4fbf\u5176\u5728 model \u7684 subscriptions \u4e2d\u76d1\u542c router \u53d8\u5316\u3002<\/p>\n<h3>3.3 dva\/fetch<\/h3>\n<p>\u5f02\u6b65\u8bf7\u6c42\u5e93\uff0c\u8f93\u51fa isomorphic-fetch \u7684\u63a5\u53e3\u3002<\/p>\n<h3>3.4 dva-loading<\/h3>\n<p>dva \u6709\u4e00\u4e2a\u7ba1\u7406 effects \u6267\u884c\u7684 hook\uff0c\u5e76\u57fa\u4e8e\u6b64\u5c01\u88c5\u4e86 dva-loading \u63d2\u4ef6\u3002\u901a\u8fc7\u8fd9\u4e2a\u63d2\u4ef6\uff0c\u6211\u4eec\u53ef\u4ee5\u4e0d\u5fc5\u4e00\u904d\u904d\u5730\u5199 showLoading \u548c hideLoading\uff0c\u5f53\u53d1\u8d77\u8bf7\u6c42\u65f6\uff0c\u63d2\u4ef6\u4f1a\u81ea\u52a8\u8bbe\u7f6e\u6570\u636e\u91cc\u7684 loading \u72b6\u6001\u4e3a true \u6216 false \u3002\u7136\u540e\u6211\u4eec\u5728\u6e32\u67d3 components \u65f6\u7ed1\u5b9a\u5e76\u6839\u636e\u8fd9\u4e2a\u6570\u636e\u8fdb\u884c\u6e32\u67d3\u3002<\/p>\n<pre><code class=\"language-javascript\">\/\/ 1\u3001\u6ce8\u518c dva-loading \u63d2\u4ef6\nimport dva from &#039;dva&#039;;\nimport createLoading from &#039;dva-loading&#039;;\nconst app = dva();\napp.use(createLoading());\n\n\/\/ 2\u3001\u4ecestore\u4e2d\u83b7\u53d6loading\u72b6\u6001\nimport React from &#039;react&#039;;\nimport { connect } from &#039;dva&#039;;\nimport { Table } from &#039;antd&#039;;\n\nfunction Users({ dispatch, list: dataSource, loading }) {\n  const columns = [\n    {\n      title: &#039;Username&#039;,\n      dataIndex: &#039;username&#039;,\n      key: &#039;username&#039;,\n      render: text =&gt; &lt;a href=&quot;&quot;&gt;{text}&lt;\/a&gt;,\n    },\n    {\n      title: &#039;Street&#039;,\n      dataIndex: &#039;address.street&#039;,\n      key: &#039;street&#039;,\n    },\n    {\n      title: &#039;Website&#039;,\n      dataIndex: &#039;website&#039;,\n      key: &#039;website&#039;,\n    }\n  ];\n\n  return (\n    &lt;div className={styles.normal}&gt;\n      &lt;Table\n        columns={columns}\n        dataSource={dataSource}\n        loading={loading}\n        rowKey={record =&gt; record.id}\n        pagination={false}\n      \/&gt;\n    &lt;\/div&gt;\n  );\n}\n\nfunction mapStateToProps(state) {\n  const { list } = state.users;\n  return {\n    loading: state.loading.models.users,\n    list,\n  };\n}\n\nexport default connect(mapStateToProps)(Users);<\/code><\/pre>\n<h3>3.5 Fragment<\/h3>\n<p>React \u4e2d\u5e38\u89c1\u6a21\u5f0f\u662f\u4e3a\u4e00\u4e2a\u7ec4\u4ef6\u8fd4\u56de\u591a\u4e2a\u5143\u7d20\u3002\u4e3a\u4e86\u5305\u88f9\u591a\u4e2a\u5143\u7d20\u6211\u4eec\u5199\u8fc7\u5f88\u591a\u7684 div \u548c span\uff0c\u8fdb\u884c\u4e0d\u5fc5\u8981\u7684\u5d4c\u5957\uff0c\u65e0\u5f62\u4e2d\u589e\u52a0\u4e86\u6d4f\u89c8\u5668\u7684\u6e32\u67d3\u538b\u529b\u3002<\/p>\n<p>react15\u7248\u4ee5\u524d\uff0crender \u51fd\u6570\u7684\u8fd4\u56de\u5fc5\u987b\u6709\u4e00\u4e2a\u6839\u8282\u70b9\uff0c\u5426\u5219\u62a5\u9519\uff0c\u4e3a\u6ee1\u8db3\u8fd9\u4e00\u539f\u5219\u6211\u4f1a\u4f7f\u7528\u4e00\u4e2a\u6ca1\u6709\u4efb\u4f55\u6837\u5f0f\u7684 div \u5305\u88f9\u4e00\u4e0b\u3002<\/p>\n<pre><code class=\"language-javascript\">import React from &#039;react&#039;;\nexport default function () {\n    return (\n        &lt;div&gt;\n            &lt;div&gt;\u4e00\u6b65 01&lt;\/div&gt;\n            &lt;div&gt;\u4e00\u6b65 02&lt;\/div&gt;\n            &lt;div&gt;\u4e00\u6b65 03&lt;\/div&gt;\n        &lt;\/div&gt;\n    );\n}<\/code><\/pre>\n<p>react 16\u7248\u5f00\u59cb\uff0c render\u652f\u6301\u8fd4\u56de\u6570\u7ec4\uff0c\u8fd9\u4e00\u7279\u6027\u5df2\u7ecf\u53ef\u4ee5\u51cf\u5c11\u4e0d\u5fc5\u8981\u8282\u70b9\u5d4c\u5957<\/p>\n<pre><code class=\"language-javascript\">import React from &#039;react&#039;;\nexport default function () {\n    return [\n        &lt;div&gt;\u4e00\u6b65 01&lt;\/div&gt;,\n        &lt;div&gt;\u4e00\u6b65 02&lt;\/div&gt;,\n        &lt;div&gt;\u4e00\u6b65 03&lt;\/div&gt;\n    ];\n}<\/code><\/pre>\n<p>\u800c\u4e14React 16\u4e3a\u6211\u4eec\u63d0\u4f9b\u4e86Fragment\u3002Fragment\u4e0eVue.js\u7684 &lt;template&gt; \u529f\u80fd\u7c7b\u4f3c\uff0c\u53ef\u505a\u4e0d\u53ef\u89c1\u7684\u5305\u88f9\u5143\u7d20\u3002<\/p>\n<pre><code class=\"language-javascript\">import React from &#039;react&#039;;\nexport default function () {\n    return (\n        &lt;React.Fragment&gt;\n            &lt;div&gt;\u4e00\u6b65 01&lt;\/div&gt;\n            &lt;div&gt;\u4e00\u6b65 02&lt;\/div&gt;\n            &lt;div&gt;\u4e00\u6b65 03&lt;\/div&gt;\n        &lt;\/React.Fragment&gt;\n    );\n}<\/code><\/pre>\n<p>\u53c2\u8003\uff1a<a href=\"https:\/\/segmentfault.com\/a\/1190000013220508\">https:\/\/segmentfault.com\/a\/1190000013220508<\/a><\/p>\n<h2>4 \u9644\u5f55\uff1aES6 \u76f8\u5173\u77e5\u8bc6\u70b9<\/h2>\n<h3>4.1 Generator \u51fd\u6570<\/h3>\n<p>Generator \u51fd\u6570\u662f ES6 \u63d0\u4f9b\u7684\u4e00\u79cd\u5f02\u6b65\u7f16\u7a0b\u89e3\u51b3\u65b9\u6848\uff0c\u8bed\u6cd5\u884c\u4e3a\u4e0e\u4f20\u7edf\u51fd\u6570\u5b8c\u5168\u4e0d\u540c\u3002<\/p>\n<p>\u5f62\u5f0f\u4e0a\uff0cGenerator \u51fd\u6570\u662f\u4e00\u4e2a\u666e\u901a\u51fd\u6570\uff0c\u4f46\u662f\u6709\u4e24\u4e2a\u7279\u5f81\u3002\u4e00\u662f\uff0c<code>function<\/code> \u5173\u952e\u5b57\u4e0e\u51fd\u6570\u540d\u4e4b\u95f4\u6709\u4e00\u4e2a\u661f\u53f7\uff1b\u4e8c\u662f\uff0c\u51fd\u6570\u4f53\u5185\u90e8\u4f7f\u7528<code>yield<\/code>\u8868\u8fbe\u5f0f\uff0c\u5b9a\u4e49\u4e0d\u540c\u7684\u5185\u90e8\u72b6\u6001\u3002<\/p>\n<p>Generator \u51fd\u6570\u6709\u591a\u79cd\u7406\u89e3\u89d2\u5ea6\u3002\u8bed\u6cd5\u4e0a\uff0c\u9996\u5148\u53ef\u4ee5\u628a\u5b83\u7406\u89e3\u6210\uff0cGenerator \u51fd\u6570\u662f\u4e00\u4e2a\u72b6\u6001\u673a\uff0c\u5c01\u88c5\u4e86\u591a\u4e2a\u5185\u90e8\u72b6\u6001\u3002\u6267\u884c Generator \u51fd\u6570\u4f1a\u8fd4\u56de\u4e00\u4e2a\u904d\u5386\u5668\u5bf9\u8c61\uff0c\u4e5f\u5c31\u662f\u8bf4\uff0cGenerator \u51fd\u6570\u9664\u4e86\u72b6\u6001\u673a\uff0c\u8fd8\u662f\u4e00\u4e2a\u904d\u5386\u5668\u5bf9\u8c61\u751f\u6210\u51fd\u6570\u3002\u8fd4\u56de\u7684\u904d\u5386\u5668\u5bf9\u8c61\uff0c\u53ef\u4ee5\u4f9d\u6b21\u904d\u5386 Generator \u51fd\u6570\u5185\u90e8\u7684\u6bcf\u4e00\u4e2a\u72b6\u6001\u3002<\/p>\n<pre><code class=\"language-javascript\">function* helloWorldGenerator() {\n  yield &#039;hello&#039;;\n  yield &#039;world&#039;;\n  return &#039;ending&#039;;\n}\nvar hw = helloWorldGenerator();<\/code><\/pre>\n<p>\u4e0a\u9762\u4ee3\u7801\u5b9a\u4e49\u4e86\u4e00\u4e2a Generator \u51fd\u6570<code>helloWorldGenerator<\/code>\uff0c\u5b83\u5185\u90e8\u6709\u4e24\u4e2a<code>yield<\/code>\u8868\u8fbe\u5f0f\uff08<code>hello<\/code>\u548c<code>world<\/code>\uff09\uff0c\u5373\u8be5\u51fd\u6570\u6709\u4e09\u4e2a\u72b6\u6001\uff1ahello\uff0cworld \u548c return \u8bed\u53e5\uff08\u7ed3\u675f\u6267\u884c\uff09\u3002<\/p>\n<p>\u7136\u540e\uff0cGenerator \u51fd\u6570\u7684\u8c03\u7528\u65b9\u6cd5\u4e0e\u666e\u901a\u51fd\u6570\u4e00\u6837\uff0c\u4e5f\u662f\u5728\u51fd\u6570\u540d\u540e\u9762\u52a0\u4e0a\u4e00\u5bf9\u5706\u62ec\u53f7\u3002\u4e0d\u540c\u7684\u662f\uff0c\u8c03\u7528 Generator \u51fd\u6570\u540e\uff0c\u8be5\u51fd\u6570\u5e76\u4e0d\u6267\u884c\uff0c\u8fd4\u56de\u7684\u4e5f\u4e0d\u662f\u51fd\u6570\u8fd0\u884c\u7ed3\u679c\uff0c\u800c\u662f\u4e00\u4e2a\u6307\u5411\u5185\u90e8\u72b6\u6001\u7684\u6307\u9488\u5bf9\u8c61\u2014\u904d\u5386\u5668\u5bf9\u8c61\u3002<\/p>\n<p>\u4e0b\u4e00\u6b65\uff0c\u5fc5\u987b\u8c03\u7528\u904d\u5386\u5668\u5bf9\u8c61\u7684<code>next<\/code>\u65b9\u6cd5\uff0c\u4f7f\u5f97\u6307\u9488\u79fb\u5411\u4e0b\u4e00\u4e2a\u72b6\u6001\u3002\u4e5f\u5c31\u662f\u8bf4\uff0c\u6bcf\u6b21\u8c03\u7528<code>next<\/code>\u65b9\u6cd5\uff0c\u5185\u90e8\u6307\u9488\u5c31\u4ece\u51fd\u6570\u5934\u90e8\u6216\u4e0a\u4e00\u6b21\u505c\u4e0b\u6765\u7684\u5730\u65b9\u5f00\u59cb\u6267\u884c\uff0c\u76f4\u5230\u9047\u5230\u4e0b\u4e00\u4e2a<code>yield<\/code>\u8868\u8fbe\u5f0f\uff08\u6216<code>return<\/code>\u8bed\u53e5\uff09\u4e3a\u6b62\u3002\u6362\u8a00\u4e4b\uff0cGenerator \u51fd\u6570\u662f\u5206\u6bb5\u6267\u884c\u7684\uff0c<code>yield<\/code>\u8868\u8fbe\u5f0f\u662f\u6682\u505c\u6267\u884c\u7684\u6807\u8bb0\uff0c\u800c<code>next<\/code>\u65b9\u6cd5\u53ef\u4ee5\u6062\u590d\u6267\u884c\u3002<\/p>\n<pre><code class=\"language-javascript\">hw.next() \/\/ { value: &#039;hello&#039;, done: false }\nhw.next() \/\/ { value: &#039;world&#039;, done: false }\nhw.next() \/\/ { value: &#039;ending&#039;, done: true }\nhw.next() \/\/ { value: undefined, done: true }<\/code><\/pre>\n<p>\u904d\u5386\u5668\u5bf9\u8c61\u7684<code>next<\/code>\u65b9\u6cd5\u7684\u8fd0\u884c\u903b\u8f91\u5982\u4e0b\u3002<\/p>\n<p>\uff081\uff09\u9047\u5230<code>yield<\/code>\u8868\u8fbe\u5f0f\uff0c\u5c31\u6682\u505c\u6267\u884c\u540e\u9762\u7684\u64cd\u4f5c\uff0c\u5e76\u5c06\u7d27\u8ddf\u5728<code>yield<\/code>\u540e\u9762\u7684\u90a3\u4e2a\u8868\u8fbe\u5f0f\u7684\u503c\uff0c\u4f5c\u4e3a\u8fd4\u56de\u7684\u5bf9\u8c61\u7684<code>value<\/code>\u5c5e\u6027\u503c\u3002<\/p>\n<p>\uff082\uff09\u4e0b\u4e00\u6b21\u8c03\u7528<code>next<\/code>\u65b9\u6cd5\u65f6\uff0c\u518d\u7ee7\u7eed\u5f80\u4e0b\u6267\u884c\uff0c\u76f4\u5230\u9047\u5230\u4e0b\u4e00\u4e2a<code>yield<\/code>\u8868\u8fbe\u5f0f\u3002<\/p>\n<p>\uff083\uff09\u5982\u679c\u6ca1\u6709\u518d\u9047\u5230\u65b0\u7684<code>yield<\/code>\u8868\u8fbe\u5f0f\uff0c\u5c31\u4e00\u76f4\u8fd0\u884c\u5230\u51fd\u6570\u7ed3\u675f\uff0c\u76f4\u5230<code>return<\/code>\u8bed\u53e5\u4e3a\u6b62\uff0c\u5e76\u5c06<code>return<\/code>\u8bed\u53e5\u540e\u9762\u7684\u8868\u8fbe\u5f0f\u7684\u503c\uff0c\u4f5c\u4e3a\u8fd4\u56de\u7684\u5bf9\u8c61\u7684<code>value<\/code>\u5c5e\u6027\u503c\u3002<\/p>\n<p>\uff084\uff09\u5982\u679c\u8be5\u51fd\u6570\u6ca1\u6709<code>return<\/code>\u8bed\u53e5\uff0c\u5219\u8fd4\u56de\u7684\u5bf9\u8c61\u7684<code>value<\/code>\u5c5e\u6027\u503c\u4e3a<code>undefined<\/code>\u3002<\/p>\n<p>\u603b\u7ed3\u4e00\u4e0b\uff0c\u8c03\u7528 Generator \u51fd\u6570\uff0c\u8fd4\u56de\u4e00\u4e2a\u904d\u5386\u5668\u5bf9\u8c61\uff0c\u4ee3\u8868 Generator \u51fd\u6570\u7684\u5185\u90e8\u6307\u9488\u3002\u4ee5\u540e\uff0c\u6bcf\u6b21\u8c03\u7528\u904d\u5386\u5668\u5bf9\u8c61\u7684<code>next<\/code>\u65b9\u6cd5\uff0c\u5c31\u4f1a\u8fd4\u56de\u4e00\u4e2a\u6709\u7740<code>value<\/code>\u548c<code>done<\/code>\u4e24\u4e2a\u5c5e\u6027\u7684\u5bf9\u8c61\u3002<code>value<\/code>\u5c5e\u6027\u8868\u793a\u5f53\u524d\u7684\u5185\u90e8\u72b6\u6001\u7684\u503c\uff0c\u662f<code>yield<\/code>\u8868\u8fbe\u5f0f\u540e\u9762\u90a3\u4e2a\u8868\u8fbe\u5f0f\u7684\u503c\uff1b<code>done<\/code>\u5c5e\u6027\u662f\u4e00\u4e2a\u5e03\u5c14\u503c\uff0c\u8868\u793a\u662f\u5426\u904d\u5386\u7ed3\u675f\u3002\u53e6\u5916\u9700\u8981\u6ce8\u610f\uff0c<code>yield<\/code>\u8868\u8fbe\u5f0f\u53ea\u80fd\u7528\u5728 Generator \u51fd\u6570\u91cc\u9762\uff0c\u7528\u5728\u5176\u4ed6\u5730\u65b9\u90fd\u4f1a\u62a5\u9519\u3002<\/p>\n<h3>4.2 Generator \u51fd\u6570\u7684\u5f02\u6b65\u5e94\u7528<\/h3>\n<p>ES6 \u8bde\u751f\u4ee5\u524d\uff0c\u5f02\u6b65\u7f16\u7a0b\u7684\u65b9\u6cd5\uff0c\u5927\u6982\u6709\u56db\u79cd\uff1a\u56de\u8c03\u51fd\u6570\u3001\u4e8b\u4ef6\u76d1\u542c\u3001\u53d1\u5e03\/\u8ba2\u9605\u3001Promise \u5bf9\u8c61\u3002Generator \u51fd\u6570\u5c06 JavaScript \u5f02\u6b65\u7f16\u7a0b\u5e26\u5165\u4e86\u4e00\u4e2a\u5168\u65b0\u7684\u9636\u6bb5\u3002<\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u539f\u6587\u94fe\u63a5\uff1ahttps:\/\/www.cnblogs.com\/colorful-coco\/p\/9454315.html An&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":true,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[82],"tags":[],"class_list":["post-4115","post","type-post","status-publish","format-standard","hentry","category-react"],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/feizhaojun.com\/index.php?rest_route=\/wp\/v2\/posts\/4115","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/feizhaojun.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/feizhaojun.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/feizhaojun.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/feizhaojun.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=4115"}],"version-history":[{"count":7,"href":"https:\/\/feizhaojun.com\/index.php?rest_route=\/wp\/v2\/posts\/4115\/revisions"}],"predecessor-version":[{"id":4122,"href":"https:\/\/feizhaojun.com\/index.php?rest_route=\/wp\/v2\/posts\/4115\/revisions\/4122"}],"wp:attachment":[{"href":"https:\/\/feizhaojun.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=4115"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/feizhaojun.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=4115"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/feizhaojun.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=4115"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}