{"id":256315,"date":"2015-04-29T16:08:01","date_gmt":"2015-04-29T12:08:01","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=256315"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=256315","title":{"rendered":"\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0438\u0437\u043e\u043c\u043e\u0440\u0444\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430 React \u0438 Flummox"},"content":{"rendered":"<p> \t\t\t\u0421\u0435\u0433\u043e\u0434\u043d\u044f \u044f \u0445\u043e\u0447\u0443 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c, \u043a\u0430\u043a \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f React, Flummox \u0438 Express, \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u043e\u0435 \u0438\u0437\u043e\u043c\u043e\u0440\u0444\u043d\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435.<\/p>\n<p>  \u0418\u0434\u0435\u044f \u0438\u0437\u043e\u043c\u043e\u0440\u0444\u043d\u043e\u0441\u0442\u0438 \u0434\u0430\u0432\u043d\u043e \u0432\u0438\u0442\u0430\u043b\u0430 \u0432 \u0432\u043e\u0437\u0434\u0443\u0445\u0435, \u043d\u043e \u043d\u0438\u043a\u0442\u043e \u043d\u0435 \u0437\u043d\u0430\u043b \u044d\u0442\u043e\u0433\u043e \u0441\u043b\u043e\u0432\u0430, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0438\u0447\u0435\u0433\u043e \u043e\u0441\u043e\u0431\u043e \u043d\u0435 \u043c\u0435\u043d\u044f\u043b\u043e\u0441\u044c, \u043f\u043e\u043a\u0430 \u043d\u0435 <a href=\"http:\/\/nerds.airbnb.com\/isomorphic-javascript-future-web-apps\/\">\u043f\u0440\u0438\u0448\u0435\u043b airbnb<\/a>.<\/p>\n<p>  \u0417\u0430 \u043f\u043e\u043b\u0433\u043e\u0434\u0430 \u0434\u043e \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u044f\u0432\u0438\u043b\u0441\u044f React, \u043f\u043e\u0437\u0436\u0435 \u043f\u043e\u044f\u0432\u0438\u043b\u0441\u044f Flux \u0438 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u0435\u0433\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0439, \u043e\u0434\u043d\u0430 \u043d\u0435 \u0445\u0443\u0436\u0435 \u0434\u0440\u0443\u0433\u043e\u0439. \u041d\u043e \u0432\u0441\u0435 \u044d\u0442\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043e\u0440\u0438\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043b\u0438\u0441\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430 \u0440\u0430\u0431\u043e\u0442\u0443 \u043d\u0430 \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u043e\u0439 \u0441\u0442\u043e\u0440\u043e\u043d\u0435, \u043e\u043d\u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u043b\u0438 \u0447\u0435\u0440\u0435\u0437 \u0441\u0438\u043d\u0433\u043b\u0442\u043e\u043d\u044b \u0438, \u0437\u0430\u0447\u0430\u0441\u0442\u0443\u044e, \u0438\u0445 \u043d\u0435\u043b\u044c\u0437\u044f \u0431\u044b\u043b\u043e \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435. \u042f \u0443\u0441\u043f\u0435\u043b \u043f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e, \u043d\u043e \u043d\u0438 \u043e\u0434\u043d\u0430 \u043c\u043d\u0435 \u043d\u0435 \u043f\u043e\u043d\u0440\u0430\u0432\u0438\u043b\u0430\u0441\u044c. \u041f\u043e\u043a\u0430 \u0434\u0432\u0430 \u043c\u0435\u0441\u044f\u0446\u0430 \u043d\u0430\u0437\u0430\u0434 \u044f \u043d\u0435 \u043d\u0430\u0442\u043a\u043d\u0443\u043b\u0441\u044f \u043d\u0430 Flummox. \u041a\u0430\u043a \u0437\u0430\u044f\u0432\u043b\u044f\u0435\u0442 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a, Flummox \u0441\u043e\u0437\u0434\u0430\u043d \u043a\u0430\u043a \u0440\u0430\u0437 \u0434\u043b\u044f \u0438\u0437\u043e\u043c\u043e\u0440\u0444\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u043e\u043d \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0441\u0438\u043d\u0433\u043b\u0442\u043e\u043d\u044b, \u043f\u0440\u0438\u0441\u0443\u0449\u0438\u0435 \u0434\u0440\u0443\u0433\u0438\u043c \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f\u043c, \u0438 \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442 \u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438.<\/p>\n<p>  \u041e\u0436\u0438\u0434\u0430\u0435\u0442\u0441\u044f, \u0447\u0442\u043e \u0432\u044b \u0438\u043c\u0435\u0435\u0442\u0435 \u043e\u043f\u044b\u0442 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 React \u0438 \u0441\u043b\u044b\u0448\u0430\u043b\u0438 \u043f\u0440\u043e Flux. \u0418\u0442\u0430\u043a, \u043f\u043e\u0435\u0445\u0430\u043b\u0438\u2026<br \/>  \u0417\u0430\u0431\u0440\u0430\u0442\u044c \u0433\u043e\u0442\u043e\u0432\u044b\u0439 \u043a\u043e\u0434 \u043c\u043e\u0436\u043d\u043e <a href=\"https:\/\/github.com\/asdf404\/flummox-isomorphic-todo\">\u0442\u0443\u0442<\/a>.<br \/>  <a name=\"habracut\"><\/a>  <\/p>\n<h3>\u0428\u0430\u0433 0: \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0438\u0434\u0435\u0438<\/h3>\n<p>  \u041d\u0430\u0448\u0430 \u0438\u0434\u0435\u044f \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0432 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u0437\u0430\u043f\u0438\u0441\u0438 \u0434\u0440\u0443\u0433\u0438\u0445 \u0438\u0434\u0435\u0439. \u042d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 TODO-\u043b\u0438\u0441\u0442 (\u043a\u0430\u043a <a href=\"http:\/\/todomvc.com\/\">Todo MVC<\/a>) \u0441 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0445 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435. \u0422\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f \u0442\u0430\u043a\u0438\u0435:  <\/p>\n<ul>\n<li>\u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0437\u0430\u0434\u0430\u0447;<\/li>\n<li>\u043f\u043e\u043c\u0435\u0442\u043a\u0430 \u0437\u0430\u0434\u0430\u0447\u0438 \u043a\u0430\u043a &quot;\u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u043e&quot;;<\/li>\n<li>\u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435 (\u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u043d\u044b\u0445) \u0437\u0430\u0434\u0430\u0447;<\/li>\n<\/ul>\n<p>  \u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u044f\u044f \u043f\u0430\u043c\u044f\u0442\u044c \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430, \u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u044d\u043c\u0443\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0432\u043d\u0435\u0448\u043d\u0435\u0439 \u0411\u0414 (\u0434\u0430\u043d\u043d\u044b\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 <a href=\"https:\/\/developer.mozilla.org\/ru\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/Promise\">Promise<\/a>).<br \/>  \u0417\u0430\u043e\u0434\u043d\u043e \u043c\u044b \u0443\u0437\u043d\u0430\u0435\u043c \u043a\u0430\u043a \u0443\u0436\u0435 \u0441\u0435\u0439\u0447\u0430\u0441 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0442\u0440\u043e\u0433\u0430\u0442\u044c ES2015 \u0438 ES2016 (\u0434\u0430\u043b\u0435\u0435 \u0434\u043b\u044f \u043a\u0440\u0430\u0442\u043a\u043e\u0441\u0442\u0438 \u044f \u0431\u0443\u0434\u0443 \u043d\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u0438\u0445 ES6\/ES7) \u0432 \u0441\u0432\u043e\u0451\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438.<\/p>\n<h3>\u0428\u0430\u0433 1: \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0445 \u043f\u0430\u043a\u0435\u0442\u043e\u0432<\/h3>\n<p>  \u0414\u043b\u044f \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0443 \u043d\u0430\u0441 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f <a href=\"http:\/\/expressjs.com\/\">Express<\/a> \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0431\u044b\u043b\u043e \u0433\u043e\u043b\u043e\u0432\u043d\u043e\u0439 \u0431\u043e\u043b\u0438 \u0441 \u043d\u0438\u0437\u043a\u043e\u0443\u0440\u043e\u0432\u043d\u0435\u043d\u0432\u044b\u043c\u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430\u043c\u0438, <a href=\"http:\/\/acdlite.github.io\/flummox\">Flummox<\/a> \u0447\u0442\u043e\u0431\u044b \u043e\u043f\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u0438 <a href=\"https:\/\/facebook.github.io\/react\/\">React<\/a> \u0447\u0442\u043e\u0431\u044b \u0443\u0434\u043e\u0431\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 DOM-\u0434\u0435\u0440\u0435\u0432\u043e\u043c, \u0430 \u0447\u0442\u043e\u0431\u044b \u044d\u0442\u043e \u0432\u0441\u0451 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043d\u0430\u043c \u043d\u0443\u0436\u0435\u043d <a href=\"http:\/\/babeljs.io\/\">Babel<\/a>.<\/p>\n<p>  \u041d\u0430 \u044d\u0442\u043e\u043c \u0448\u0430\u0433\u0435 \u043c\u044b \u043f\u0440\u043e\u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u043d\u0430\u0448\u0435 Express \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c \u0431\u0430\u0437\u043e\u0432\u044b\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b.<\/p>\n<pre><code class=\"bash\">$ express $ npm install react flummox isomorphic-fetch todomvc-app-css react-router --save $ npm install babel webpack babel-core babel-loader brfs transform-loader --save-dev <\/code><\/pre>\n<p>  \u0427\u0442\u043e \u0436\u0435 \u043c\u044b \u0442\u043e\u043b\u044c\u043a\u043e \u0447\u0442\u043e \u043f\u043e\u0441\u0442\u0430\u0432\u0438\u043b\u0438, \u043f\u043e\u043c\u0438\u043c\u043e React:  <\/p>\n<ul>\n<li><code>flummox<\/code> \u2014 \u0442\u043e\u0442 \u0441\u0430\u043c\u044b\u0439 \u0438\u0437\u043e\u043c\u043e\u0440\u0444\u043d\u044b\u0439 Flux;<\/li>\n<li><code>react-router<\/code> \u2014 \u0440\u043e\u0443\u0442\u0435\u0440 \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f;<\/li>\n<li><code>isomorphic-fetch<\/code> \u2014 \u043f\u043e\u043b\u0438\u0444\u0438\u043b\u043b \u0434\u043b\u044f \u043d\u043e\u0432\u043e\u0433\u043e \u043c\u0435\u0442\u043e\u0434\u0430 <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/Fetch_API\">fetch<\/a>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0438\u0448\u0435\u043b \u043d\u0430 \u0437\u0430\u043c\u0435\u043d\u0443 XMLHttpRequest.<\/li>\n<li><code>todomvc-app-css<\/code> \u2014 \u043f\u0430\u043a\u0435\u0442 \u0441\u043e \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u043c\u0438 \u0441\u0442\u0438\u043b\u044f\u043c\u0438 \u0434\u043b\u044f TODOMVC \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439;<\/li>\n<li><code>babel<\/code>, <code>babel-core<\/code>, <code>babel-loader<\/code>, <code>brfs<\/code> \u0438 <code>transform-loader<\/code> \u2014 \u0442\u0440\u0430\u043d\u0441\u043b\u044f\u0442\u043e\u0440 ES6\/ES7 \u0432 ES5 \u0438 \u043f\u0440\u043e\u0447\u0438\u0435 \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043f\u0430\u043a\u0435\u0442\u044b, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u043f\u0440\u0438 \u0441\u0431\u043e\u0440\u043a\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f;<\/li>\n<li><code>webpack<\/code> \u2014 \u0443\u0442\u0438\u043b\u0438\u0442\u0430 \u0434\u043b\u044f \u0441\u0431\u043e\u0440\u043a\u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u043e\u0439 \u0447\u0430\u0441\u0442\u0438.<\/li>\n<\/ul>\n<p>  \u0414\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <code>babel-node<\/code>, \u0442.\u043a. \u043e\u043d \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043d\u0430 \u043b\u0435\u0442\u0443 \u0442\u0440\u0430\u043d\u0441\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c ES6\/ES7 \u043a\u043e\u0434 \u0432 ES5. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0432 <code>package.json<\/code>:<\/p>\n<pre><code class=\"javascript\">&quot;scripts&quot;: {   &quot;start&quot;: &quot;babel-node --stage 0 .\/bin\/www&quot; } <\/code><\/pre>\n<p>  <\/p>\n<h3>\u0428\u0430\u0433 2: \u0421\u043a\u0435\u043b\u0435\u0442 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f<\/h3>\n<p>  \u041f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043c \u043a \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044e \u043a\u043e\u0434\u0430 \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u043e\u0432, \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0431\u0443\u0434\u0443\u0442 \u043b\u0435\u0436\u0430\u0442\u044c \u043d\u0430\u0448\u0438 \u0444\u0430\u0439\u043b\u044b:<\/p>\n<pre><code>. \u251c\u2500\u2500 bin \u251c\u2500\u2500 client \u251c\u2500\u2500 public \u2502   \u2514\u2500\u2500 js \u251c\u2500\u2500 server \u2502   \u2514\u2500\u2500 storages \u251c\u2500\u2500 shared \u2502   \u251c\u2500\u2500 actions \u2502   \u251c\u2500\u2500 components \u2502   \u251c\u2500\u2500 handlers \u2502   \u2514\u2500\u2500 stores \u2514\u2500\u2500 utils <\/code><\/pre>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0443\u0436\u043d\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0431\u0430\u0437\u043e\u0432\u044b\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b: <code>TodoList<\/code>, <code>TodoInput<\/code> \u0438 <code>TodoItem<\/code> \u2014 \u0441\u043f\u0438\u0441\u043e\u043a, \u043f\u043e\u043b\u0435 \u0432\u0432\u043e\u0434\u0430 \u043d\u043e\u0432\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438 \u0438 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0441\u043f\u0438\u0441\u043a\u0430 (\u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0430\u044f \u0437\u0430\u0434\u0430\u0447\u0430), \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e. \u041a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0431\u0443\u0434\u0443\u0442 \u043b\u0435\u0436\u0430\u0442\u044c \u0432 \u043f\u0430\u043f\u043a\u0435 <code>shared\/components<\/code>, \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430 (stores) \u0432 \u043f\u0430\u043f\u043a\u0435 <code>shared\/stores<\/code>, \u0430 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f (actions) \u0432 \u043f\u0430\u043f\u043a\u0435 <code>shared\/actions<\/code>.<br \/>  \u041b\u043e\u0433\u0438\u043a\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0430 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u0443\u044e, \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u0443\u044e \u0438 \u043e\u0431\u0449\u0443\u044e, \u0438 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u043f\u0430\u043f\u043a\u0430\u0445 <code>server<\/code>, <code>client<\/code> \u0438 <code>shared<\/code>, \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e. \u041f\u0430\u043f\u043a\u0430 <code>shared<\/code> \u043a\u0430\u043a \u0440\u0430\u0437 \u0438 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0432\u0441\u0435 \u0438\u0437\u043e\u043c\u043e\u0440\u0444\u043d\u044b\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u0430 \u043a\u043b\u0438\u0435\u043d\u0442\u0435 \u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0435.<\/p>\n<p>  \u041a\u043e\u0434 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432, \u043d\u0443\u0436\u043d\u044b\u0445 \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f:<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">shared\/components\/TodoList.js<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\">import React from 'react'; import TodoItem from '.\/TodoItem';  class TodoList extends React.Component {     onToggleStatus(id, completed) {         this.props.onToggleStatus(id, completed);     }      onDeleteTask(id) {         this.props.onDeleteTask(id);     }      render() {         return (             &lt;ul className=&quot;todo-list&quot;&gt;                 {this.props.tasks.map(task =&gt;                     &lt;TodoItem key={task.id} task={task}                               onToggleStatus={this.onToggleStatus.bind(this, task.id)}                               onDeleteTask={this.onDeleteTask.bind(this, task.id)} \/&gt;                 )}             &lt;\/ul&gt;         );     } }  export default TodoList; <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">shared\/components\/TodoItem.js<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\">import React from 'react';  class TodoItem extends React.Component {     constructor(props) {         super(props);          this.state = props.task;     }      handleToggleStatus() {         let completed = this.refs.completed.getDOMNode().checked;         this.props.onToggleStatus(completed);         this.setState({completed});     }      handleDeleteTask() {         this.props.onDeleteTask();     }      render() {         return (             &lt;li className={this.state.completed ? 'completed' : ''}&gt;                 &lt;div className=&quot;view&quot;&gt;                     &lt;input className=&quot;toggle&quot;                            type=&quot;checkbox&quot;                            defaultChecked={this.state.completed}                            onChange={this.handleToggleStatus.bind(this)}                            ref=&quot;completed&quot; \/&gt;                     &lt;label&gt;{this.state.text}&lt;\/label&gt;                     &lt;button className=&quot;destroy&quot;                             onClick={this.handleDeleteTask.bind(this)} \/&gt;                 &lt;\/div&gt;                 &lt;input className=&quot;edit&quot; defaultValue={this.state.text} \/&gt;             &lt;\/li&gt;         );     } }  export default TodoItem; <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0432\u0441\u0435\u0445 (\u043a\u0440\u043e\u043c\u0435 API) \u043f\u043e\u0441\u0442\u0443\u043f\u0430\u044e\u0449\u0438\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u0440\u043e\u0443\u0442\u0435\u0440\u043e\u043c \u0440\u0435\u0430\u043a\u0442\u0430 (\u0441\u043c. \u043d\u0438\u0436\u0435):<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u041a\u043e\u0434<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\">app.use(async function (req, res, next) {     let flux = new Flux();      \/\/ \u0437\u0434\u0435\u0441\u044c \u0441\u043e\u0437\u0434\u0430\u0451\u0442\u0441\u044f \u0440\u043e\u0443\u0442\u0435\u0440, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u0432\u0441\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043a\u043b\u0438\u0435\u043d\u0442\u0430     let router = Router.create({         routes: routes,         location: req.url     });     let {Handler, state} = await new Promise((resolve, reject) =&gt; {         router.run((Handler, state) =&gt;             resolve({Handler, state})         );     });      \/\/ \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430, \u0441\u043c. \u0448\u0430\u0433 \u21164     await performRouteHandlerStaticMethod(state.routes, 'routerWillRun', {state, flux});      \/\/ \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0432 \u0441\u0442\u0440\u043e\u043a\u0443     let html = React.renderToString(         &lt;FluxComponent flux={flux}&gt;             &lt;Handler {...state} \/&gt;         &lt;\/FluxComponent&gt;     );          \/\/ \u043d\u0435\u0438\u0437\u043c\u0435\u043d\u044f\u0435\u043c\u044b\u0435 \u0447\u0430\u0441\u0442\u0438 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430 \u043e\u0442\u0434\u0430\u044e\u0442\u0441\u044f \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u043e\u0439, \u0442.\u043a. \u044d\u0442\u043e \u043f\u043e\u0432\u044b\u0448\u0430\u0435\u0442 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c     res.send(`         &lt;!DOCTYPE html&gt;         &lt;html&gt;             &lt;head&gt;                 &lt;meta charset=&quot;utf-8&quot;&gt;                 &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot;&gt;                 &lt;title&gt;HabraIsoTODO&lt;\/title&gt;                 &lt;link rel=&quot;stylesheet&quot; href=&quot;\/css\/index.css&quot;&gt;             &lt;\/head&gt;             &lt;body&gt;                 &lt;div id=&quot;app&quot;&gt;                     ${html}                 &lt;\/div&gt;             &lt;\/body&gt;         &lt;\/html&gt;`     ); }); <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u041e\u0442\u043b\u0438\u0447\u043d\u043e, \u0442\u0435\u043f\u0435\u0440\u044c \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u0438\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432.<\/p>\n<p>  \u0417\u0434\u0435\u0441\u044c \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u043d\u043e\u0432\u044b\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u0442\u0430\u043d\u0443\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u0432 ES7 \u2014 <a href=\"http:\/\/jakearchibald.com\/2014\/es7-async-functions\/\">async\/await<\/a>. \u041e\u043d\u0438 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0442 \u0438\u0437\u0431\u0430\u0432\u0438\u0442\u044c \u043a\u043e\u0434 \u043e\u0442 callback-hell (\u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0440\u0430\u043d\u044c\u0448\u0435 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u043b\u043e\u0441\u044c \u0440\u0435\u0448\u0430\u0442\u044c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0437\u0430\u043c\u0435\u0447\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u043c\u043e\u0434\u0443\u043b\u044f <a href=\"https:\/\/github.com\/caolan\/async\">async<\/a> \u0438\u043b\u0438 \u043f\u043e\u0434\u043e\u0431\u043d\u044b\u0445).<\/p>\n<p>  \u0421\u043e\u0432\u0435\u0442: \u043e\u0431\u0435\u0440\u043d\u0438\u0442\u0435 \u0432\u0441\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u0432\u043d\u0443\u0442\u0440\u0438 \u044d\u0442\u043e\u0433\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u0432 try-catch \u0431\u043b\u043e\u043a \u0434\u043b\u044f \u043e\u0442\u043b\u043e\u0432\u0430 \u043e\u0448\u0438\u0431\u043e\u043a. \u0422.\u043a. \u0435\u0441\u043b\u0438 \u0447\u0442\u043e-\u0442\u043e \u0441\u043b\u043e\u043c\u0430\u0435\u0442\u0441\u044f \u0432\u043d\u0443\u0442\u0440\u0438, \u0442\u043e \u0431\u0435\u0437 try-catch \u0432\u044b <a href=\"https:\/\/github.com\/babel\/babel\/issues\/1234\">\u043d\u0435 \u0443\u0432\u0438\u0434\u0438\u0442\u0435<\/a> \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0435.<\/p>\n<h3>\u0428\u0430\u0433 3: API<\/h3>\n<p>  \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u043d\u0435\u043c\u043d\u043e\u0433\u043e API, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u043a\u043b\u0438\u0435\u043d\u0442\u0443 \u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0443. \u0411\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c REST \u043f\u043e\u0434\u0445\u043e\u0434, \u0442.\u043a. \u043e\u043d \u0438\u0434\u0435\u0430\u043b\u044c\u043d\u043e \u0432\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0432 \u0434\u0430\u043d\u043d\u0443\u044e \u0437\u0430\u0434\u0430\u0447\u0443. \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u0431\u0430\u0437\u043e\u0432\u044b\u0435 \u043f\u0443\u0442\u0438:<\/p>\n<pre><code>GET    \/api\/tasks           # \u0432\u0441\u0435 \u0437\u0430\u0434\u0430\u0447\u0438 POST   \/api\/tasks           # \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0437\u0430\u0434\u0430\u0447\u0443 PUT    \/api\/tasks           # \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u0432\u0441\u0435 \u0437\u0430\u0434\u0430\u0447\u0438 GET    \/api\/tasks\/active    # \u0442\u043e\u043b\u044c\u043a\u043e \u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0435 GET    \/api\/tasks\/completed # \u0442\u043e\u043b\u044c\u043a\u043e \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u044b\u0435 DELETE \/api\/tasks\/completed # \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u044b\u0435 PUT    \/api\/tasks\/:id       # \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u0443\u044e \u0437\u0430\u0434\u0430\u0447\u0443 DELETE \/api\/tasks\/:id       # \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u0443\u044e \u0437\u0430\u0434\u0430\u0447\u0443 <\/code><\/pre>\n<p>  \u0417\u0430\u0442\u0435\u043c \u0437\u0430\u043f\u0438\u0448\u0435\u043c \u0438\u0445 \u0432 \u0432\u0438\u0434\u0435 \u0440\u043e\u0443\u0442\u043e\u0432:<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">server\/routes.js<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\">import {Router} from 'express'; import MemoryStorage from '.\/storages\/MemoryStorage'; import http from 'http';  let router = new Router(); let storage = new MemoryStorage();  router.get('\/tasks', async (req, res) =&gt; {     res.json(await storage.list()); });  router.post('\/tasks', async (req, res, next) =&gt; {     if (!req.body.text || !req.body.text.length) {         let err = new Error(http.STATUS_CODES[400]);         err.status = 400;         return next(err);     }     let task = await storage.save({         text: req.body.text.substr(0, 256),         completed: false     });     res.status(201).send(task); });  router.put('\/tasks', async (req, res) =&gt; {     let completed = req.body.completed;     let tasks = (await storage.list()).map(task =&gt; {         return storage.update(task.id, {             text: task.text,             completed: Boolean(completed)         });     });     res.status(201).json(await Promise.all(tasks)); });  router.get('\/tasks\/active', async (req, res) =&gt; {     res.json(await storage.list((task) =&gt; !task.completed)); });  router.get('\/tasks\/completed', async (req, res) =&gt; {     res.json(await storage.list((task) =&gt; task.completed)); });  router.delete('\/tasks\/completed', async (req, res, next) =&gt; {     let deleted = [];     try {         let items = await storage.list((task) =&gt; task.completed);         items.forEach(async (item) =&gt; {             deleted.push(item.id);             await storage.remove(item.id);         });         res.status(200).json({deleted});     } catch (err) {         next(err);     } });  router.get('\/tasks\/:id', async (req, res, next) =&gt; {     let id = req.params.id;     try {         var item = await storage.fetch(id);         res.status(200).send(item);     } catch (err) {         return next(err);     } });  router.put('\/tasks\/:id', async (req, res, next) =&gt; {     let id = req.params.id;     try {         var item = await storage.fetch(id);     } catch (err) {         return next(err);     }      let updated = item;     Object.keys(req.body).forEach((key) =&gt; {         updated[key] = req.body[key];     });      let task = await storage.update(id, updated);     res.status(200).json(task); });  router.delete('\/tasks\/:id', async (req, res, next) =&gt; {     let id = req.params.id;     try {         let removed = await storage.remove(id);         res.status(200).send({id, removed});     } catch (err) {         return next(err);     } });  export default router; <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0440\u0438\u043c\u043e\u043d\u0442\u0438\u0440\u0443\u0435\u043c \u0440\u043e\u0443\u0442\u044b \u043a \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c\u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044e:<\/p>\n<pre><code class=\"javascript\">import api from '.\/server\/routes'; \/\/ ... app.use('\/api', api); <\/code><\/pre>\n<p>  \u0422.\u043a. \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043e\u043b\u0436\u043d\u044b \u0433\u0434\u0435-\u0442\u043e \u0445\u0440\u0430\u043d\u0438\u0442\u044c\u0441\u044f, \u0442\u043e \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435:<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">server\/storages\/MemoryStorage.js<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\">import http from 'http';  function clone(obj) {     return JSON.parse(JSON.stringify(obj)); }  export default class MemoryStorage {     constructor() {         this._items = {             1: {                 id: 1,                 text: 'Rule the World',                 completed: false             },             2: {                 id: 2,                 text: 'Be an Awesome',                 completed: true             }         };     }      count() {         return new Promise((resolve) =&gt; {             resolve(Object.keys(this._items).length);         });     }      save(item) {         return new Promise((resolve) =&gt; {             let obj = clone(item);             obj.id = Math.round(Math.random() * 10000000).toString(36);             this._items[obj.id] = obj;             resolve(obj);         });     }      fetch(id) {         return new Promise((resolve, reject) =&gt; {             if (!this._items[id]) {                 let err = new Error(http.STATUS_CODES[404]);                 err.status = 404;                 return reject(err);             }             resolve(this._items[id]);         });     }      update(id, item) {         return new Promise((resolve, reject) =&gt; {             let obj = clone(item);             let existed = this._items[id];             if (!existed) {                 let err = new Error(http.STATUS_CODES[404]);                 err.status = 404;                 return reject(err);             }              obj.id = existed.id;             this._items[obj.id] = obj;             resolve(obj);         });     }      remove(id) {         return new Promise((resolve, reject) =&gt; {             if (!this._items[id]) {                 let err = new Error(http.STATUS_CODES[404]);                 err.status = 404;                 return reject(err);             }             delete this._items[id];             resolve(true);         });     }      list(check) {         return new Promise((resolve) =&gt; {             let items = Object.keys(this._items).map((key) =&gt; this._items[key]).reduce((memo, item) =&gt; {                 if (check && check(item)) {                     memo.push(item);                 } else if (!check) {                     memo.push(item);                 }                 return memo;             }, []);              resolve(items);         });     } } <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u042d\u0442\u043e\u0442 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0431\u0443\u0434\u0435\u0442 \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043d\u0430\u0448\u0438 \u0437\u0430\u0434\u0430\u0447\u0438 \u0432 \u043f\u0430\u043c\u044f\u0442\u0438 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430. \u0412\u043d\u0438\u043c\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0447\u0438\u0442\u0430\u0442\u0435\u043b\u044c \u043c\u043e\u0433 \u0437\u0430\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e \u043c\u044b \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c Promise \u0438\u0437 \u0432\u0441\u0435\u0445 \u043c\u0435\u0442\u043e\u0434\u043e\u0432. \u042d\u0442\u043e \u043a\u0430\u043a \u0440\u0430\u0437 \u0442\u043e \u043c\u0435\u0441\u0442\u043e, \u0433\u0434\u0435 \u044d\u043c\u0443\u043b\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0440\u0430\u0431\u043e\u0442\u0430 \u0441 \u0432\u043d\u0435\u0448\u043d\u0435\u0439 \u0411\u0414.<\/p>\n<p>  \u0422\u0430\u043a\u0436\u0435 \u0432\u0438\u0434\u043d\u043e, \u0447\u0442\u043e \u044d\u0442\u043e\u0442 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0432 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043c\u0435\u0442\u043e\u0434\u0430\u0445 \u0431\u0440\u043e\u0441\u0430\u0435\u0442 HTTP \u043e\u0448\u0438\u0431\u043a\u0438. \u0412 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u043c\u0438\u0440\u0435 \u0442\u0430\u043a \u0434\u0435\u043b\u0430\u0442\u044c \u043d\u0435\u043b\u044c\u0437\u044f, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u0437\u043d\u0430\u0442\u044c \u043f\u0440\u043e HTTP.<\/p>\n<h3>\u0428\u0430\u0433 4: \u041a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0438 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435<\/h3>\n<p>  API \u044d\u0442\u043e, \u043a\u043e\u043d\u0435\u0447\u043d\u043e \u0445\u043e\u0440\u043e\u0448\u043e, \u043d\u043e \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0435\u0449\u0451 \u0432\u0441\u0451 \u0441\u0432\u044f\u0437\u0430\u0442\u044c \u0441 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430\u043c\u0438. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043d\u0430\u0431\u043e\u0440 Action&#39;\u043e\u0432 \u0438 Store, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438 \u0431\u0443\u0434\u0443\u0442 \u043e\u0431\u0449\u0430\u0442\u044c\u0441\u044f \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0434\u043b\u044f \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0438 \u0432 \u043d\u0430\u0448\u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b.<\/p>\n<p>  \u0421\u043f\u0435\u0440\u0432\u0430 \u043e\u0431\u044a\u044f\u0432\u0438\u043c \u043d\u0430\u0448\u0438 Action \u0438 Store \u0432 \u0433\u043b\u0430\u0432\u043d\u043e\u043c \u043a\u043b\u0430\u0441\u0441\u0435 Flux&#39;\u0430:<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">shared\/Flux.js<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\">import {Flux} from 'flummox'; import TodoListAction from '.\/actions\/TodoActions'; import TodoListStore from '.\/stores\/TodoStore';  export default class extends Flux {     constructor() {         super();          this.createActions('todo', TodoListAction);         this.createStore('todo', TodoListStore, this);     } } <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0417\u0434\u0435\u0441\u044c \u043c\u044b \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043b\u0438 \u043d\u0430\u0448\u0438 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0438 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u043f\u043e\u0434 \u0438\u043c\u0435\u043d\u0435\u043c <code>todo<\/code>. \u041f\u043e \u044d\u0442\u043e\u043c\u0443 \u0438\u043c\u0435\u043d\u0438 \u043c\u044b \u0441\u043c\u043e\u0436\u0435\u043c \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0438\u0445 \u0432 \u043b\u044e\u0431\u043e\u043c \u043c\u0435\u0441\u0442\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043e\u0431\u044a\u044f\u0432\u0438\u043c \u0441\u0430\u043c\u0438 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0438 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435:<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">shared\/actions\/TodoActions.js<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\">import {Actions} from 'flummox'; import fetch from 'isomorphic-fetch';  \/\/ \u043c\u044b \u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u043f\u0440\u043e\u043f\u0438\u0448\u0435\u043c \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u0445\u043e\u0441\u0442, \u0442.\u043a. \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435 \u0443 \u043d\u0430\u0441 \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c location.host const API_HOST = 'http:\/\/localhost:3000';  class TodoListActions extends Actions {     async getTasks() {         return (await fetch(`${API_HOST}\/api\/tasks`, {             headers: {                 'Accept': 'application\/json'             }         })).json();     }      async getActiveTasks() {         return (await fetch(`${API_HOST}\/api\/tasks\/active`, {             headers: {                 'Accept': 'application\/json'             }         })).json();     }      async getCompletedTasks() {         return (await fetch(`${API_HOST}\/api\/tasks\/completed`, {             headers: {                 'Accept': 'application\/json'             }         })).json();     }      async deleteCompletedTasks() {         return (await fetch(`${API_HOST}\/api\/tasks\/completed`, {             method: 'DELETE',             headers: {                 'Accept': 'application\/json'             }         })).json();     }      async createTask(task) {         return (await fetch(`${API_HOST}\/api\/tasks`, {             method: 'POST',             headers: {                 'Accept': 'application\/json',                 'Content-Type': 'application\/json'             },             body: JSON.stringify(task)         })).json();     }      async deleteTask(id) {         return (await fetch(`${API_HOST}\/api\/tasks\/${id}`, {             method: 'DELETE',             headers: {                 'Accept': 'application\/json'             }         })).json();     }      async toggleTask(id, completed) {         return (await fetch(`${API_HOST}\/api\/tasks\/${id}`, {             method: 'PUT',             headers: {                 'Accept': 'application\/json',                 'Content-Type': 'application\/json'             },             body: JSON.stringify({completed})         })).json();     }      async toggleAll(completed) {         return (await fetch(`${API_HOST}\/api\/tasks`, {             method: 'PUT',             headers: {                 'Accept': 'application\/json',                 'Content-Type': 'application\/json'             },             body: JSON.stringify({completed})         })).json();     } }  export default TodoListActions; <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">shared\/stores\/TodoStore.js<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\"> import {Store} from 'flummox';  class TodoListStore extends Store {     constructor(flux) {         super();          let actions = flux.getActionIds('todo');          \/\/ \u0441\u0432\u044f\u0437\u044b\u0432\u0430\u043d\u0438\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439 \u0438 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430         this.register(actions.getTasks, this.handleNewTasks);         this.register(actions.getActiveTasks, this.handleNewTasks);         this.register(actions.getCompletedTasks, this.handleNewTasks);         this.register(actions.createTask, this.handleNewTask);         this.register(actions.toggleTask, this.handleUpdateTask);         this.register(actions.toggleAll, this.handleNewTasks);         this.register(actions.deleteTask, this.handleDeleteTask);         this.register(actions.deleteCompletedTasks, this.handleDeleteTasks);     }      handleNewTask(task) {         if (task && task.id) {             this.setState({                 tasks: this.state.tasks.concat([task])             });         }     }      handleNewTasks(tasks) {         this.setState({             tasks: tasks ? tasks : []         });     }      handleUpdateTask(task) {         let id = task.id;         this.setState({             tasks: this.state.tasks.map(t =&gt; {                 return (t.id == id) ? task : t;             })         });     }      handleDeleteTask(task) {         let id = task.id;         this.setState({             tasks: this.state.tasks.map(t =&gt; {                 if (t.id != id) {                     return t;                 }             }).filter(Boolean)         });     }      handleDeleteTasks({deleted}) {         this.setState({             tasks: this.state.tasks.filter(task =&gt;                 deleted.indexOf(task.id) &lt; 0             )         });     } }  export default TodoListStore; <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u041d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435, \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c \u043e\u0431\u0449\u0430\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e Action, \u0430 Store \u043b\u0438\u0448\u044c \u0445\u0440\u0430\u043d\u0438\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438 \u0441\u0432\u044f\u0437\u044b\u0432\u0430\u0435\u0442 \u0438\u0445 \u0441 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430\u043c\u0438.<\/p>\n<p>  \u0412 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430 (<code>TodoStore<\/code>) \u043c\u044b \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u043c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u043f\u0440\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430.<\/p>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043f\u043e\u0441\u043b\u0435 \u0432\u044b\u0437\u043e\u0432\u0430 \u043c\u0435\u0442\u043e\u0434\u0430 \u0438\u0437 Action&#39;\u0430, \u043e\u043d \u0431\u0443\u0434\u0435\u0442 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0442\u044c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 Store, \u0430 \u0442\u043e\u0442, \u0432 \u0441\u0432\u043e\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c, \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430.<\/p>\n<h3>\u0428\u0430\u0433 5: \u0420\u043e\u0443\u0442\u0438\u043d\u0433<\/h3>\n<p>  \u041e\u0434\u043d\u043e\u0439 \u0438\u0437 \u0432\u0430\u0436\u043d\u0435\u0439\u0448\u0438\u0445 \u0441\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u0445 \u043b\u044e\u0431\u043e\u0433\u043e \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0440\u043e\u0443\u0442\u0438\u043d\u0433. \u041a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u0438\u0439 \u0440\u043e\u0443\u0442\u0438\u043d\u0433 \u043e\u0442\u0434\u0430\u0451\u0442\u0441\u044f \u0432 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0440\u0435\u0430\u043a\u0442\u0430 \u0438 \u0443\u0436\u0435 \u043e\u043d \u0440\u0435\u0448\u0430\u0435\u0442 \u0447\u0442\u043e \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c.<br \/>  <code>react-router<\/code> \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0437\u0430\u0434\u0430\u0432\u0430\u0442\u044c \u043f\u0443\u0442\u0438 \u0432 \u0434\u0435\u043a\u043b\u0430\u0440\u0430\u0442\u0438\u0432\u043d\u043e\u043c \u0441\u0442\u0438\u043b\u0435, \u0447\u0442\u043e \u043a\u0430\u043a \u0440\u0430\u0437 \u0432 \u0434\u0443\u0445\u0435 React&#39;\u0430. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043e\u0431\u044a\u044f\u0432\u0438\u043c \u043d\u0443\u0436\u043d\u044b\u0435 \u043d\u0430\u043c \u043f\u0443\u0442\u0438:<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">client\/routes.js<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\">import React from 'react'; import {Route, DefaultRoute, NotFoundRoute} from 'react-router'; import AppHandler from '..\/shared\/handlers\/AppHandler'; import TodoHandler from '..\/shared\/handlers\/TodoHandler';  export default (     &lt;Route handler={AppHandler}&gt;         &lt;DefaultRoute handler={TodoHandler} \/&gt;         &lt;Route name=&quot;all&quot; path=&quot;\/&quot; handler={TodoHandler} action=&quot;all&quot; \/&gt;         &lt;Route name=&quot;active&quot; path=&quot;\/active&quot; handler={TodoHandler} action=&quot;active&quot; \/&gt;         &lt;Route name=&quot;completed&quot; path=&quot;\/completed&quot; handler={TodoHandler} action=&quot;completed&quot; \/&gt;     &lt;\/Route&gt; ); <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u041a\u0430\u043a \u0432\u0438\u0434\u043d\u043e, \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0430 \u0435\u0441\u0442\u044c \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a (handler). \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u0432 \u043d\u0430\u0448\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u0431\u0443\u0434\u0443\u0442 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u0438 \u044f\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u0442.\u043d. &quot;\u0443\u043c\u043d\u044b\u043c\u0438&quot; (\u0441\u043c. \u043f\u0440\u0438\u043a\u0440\u0435\u043f\u043b\u0451\u043d\u043d\u044b\u0435 \u0441\u0441\u044b\u043b\u043a\u0438) \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430\u043c\u0438. \u0418\u0445 \u0431\u0443\u0434\u0435\u0442 \u0434\u0432\u0430:<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">shared\/handlers\/AppHandler.js<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\">import React from 'react'; import {RouteHandler} from 'react-router';  class AppHandler extends React.Component {     render() {         return (             &lt;div&gt;                 &lt;section className=&quot;todoapp&quot;&gt;                     &lt;RouteHandler {...this.props} key={this.props.pathname} \/&gt;                 &lt;\/section&gt;             &lt;\/div&gt;         );     } }  export default AppHandler; <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">shared\/handlers\/TodoHandler.js<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\">import React from 'react'; import Flux from 'flummox\/component'; import TodoList from '..\/components\/TodoList'; import TodoInput from '..\/components\/TodoInput'; import ItemsCounter from '..\/components\/ItemsCounter'; import ToggleAll from '..\/components\/ToggleAll';  class TodoHandler extends React.Component {     static async routerWillRun({flux, state}) {         let action = state.routes[state.routes.length - 1].name;         let todoActions = flux.getActions('todo');         switch (action) {             case 'active':                 await todoActions.getActiveTasks();                 break;             case 'completed':                 await todoActions.getCompletedTasks();                 break;             case 'all':             default:                 await todoActions.getTasks();                 break;         }     }      async handleNewTask(text) {         let actions = this.props.flux.getActions('todo');         await actions.createTask({text});     }      async handleToggleStatus(id, status) {         let actions = this.props.flux.getActions('todo');         await actions.toggleTask(id, status);     }      async handleToggleAll(status) {         let actions = this.props.flux.getActions('todo');         await actions.toggleAll(status);     }      async handleDeleteTask(id) {         let actions = this.props.flux.getActions('todo');         await actions.deleteTask(id);     }      async handleDeleteCompletedTasks(id) {         let actions = this.props.flux.getActions('todo');         await actions.deleteCompletedTasks();     }      render() {         return (             &lt;div&gt;                 &lt;header className=&quot;header&quot;&gt;                     &lt;h1&gt;todos&lt;\/h1&gt;                     &lt;TodoInput handleNewTask={this.handleNewTask.bind(this)} \/&gt;                 &lt;\/header&gt;                 &lt;section className=&quot;main&quot;&gt;                     &lt;Flux connectToStores={['todo']}&gt;                         &lt;ToggleAll onToggleStatus={this.handleToggleAll.bind(this)} \/&gt;                     &lt;\/Flux&gt;                     &lt;Flux connectToStores={['todo']}&gt;                         &lt;TodoList onToggleStatus={this.handleToggleStatus.bind(this)}                                   onDeleteTask={this.handleDeleteTask.bind(this)} \/&gt;                     &lt;\/Flux&gt;                 &lt;\/section&gt;                 &lt;footer className=&quot;footer&quot;&gt;                     &lt;Flux connectToStores={['todo']}&gt;                         &lt;ItemsCounter count={0} \/&gt;                     &lt;\/Flux&gt;                     &lt;ul className=&quot;filters&quot;&gt;                         &lt;li&gt;                             &lt;a href=&quot;\/&quot;&gt;All&lt;\/a&gt;                         &lt;\/li&gt;                         &lt;li&gt;                             &lt;a href=&quot;\/active&quot;&gt;Active&lt;\/a&gt;                         &lt;\/li&gt;                         &lt;li&gt;                             &lt;a href=&quot;\/completed&quot;&gt;Completed&lt;\/a&gt;                         &lt;\/li&gt;                     &lt;\/ul&gt;                     &lt;button className=&quot;clear-completed&quot; onClick={this.handleDeleteCompletedTasks.bind(this)}&gt;                         Clear completed                     &lt;\/button&gt;                 &lt;\/footer&gt;             &lt;\/div&gt;         );     } }  export default TodoHandler; <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u041a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 <code>TodoHandler<\/code> \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f &quot;\u0443\u043c\u043d\u044b\u043c&quot; \u0438 \u0432\u044b \u043c\u043e\u0433\u043b\u0438 \u0437\u0430\u043c\u0435\u0442\u0438\u0442\u044c \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u043c\u0435\u0442\u043e\u0434 <code>routerWillRun<\/code>, \u0438\u043c\u0435\u043d\u043d\u043e \u0442\u0430\u043c \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u0435\u0440\u0432\u043e\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u0430\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 Store. \u041a\u0430\u043a \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u044d\u0442\u043e\u0442 \u043c\u0435\u0442\u043e\u0434 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u043e \u043d\u0438\u0436\u0435. \u041e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b, \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u0431\u0443\u0434\u0443\u0442 &quot;\u0433\u043b\u0443\u043f\u044b\u043c\u0438&quot; \u0438 \u043b\u0438\u0448\u044c \u0440\u0435\u0430\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043d\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u043e\u043a\u0440\u0443\u0436\u0430\u044e\u0449\u0435\u0433\u043e \u043c\u0438\u0440\u0430 \u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u043e\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f.<\/p>\n<p>  \u0422\u0430\u043a\u0436\u0435 \u0432\u0438\u0434\u043d\u043e, \u0447\u0442\u043e \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u043e\u0431\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u0432 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 <code>&lt;Flux \/&gt;<\/code>. \u0415\u0433\u043e \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e <code>connectToStores<\/code> \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u0441\u0432\u044f\u0437\u044c \u043c\u0435\u0436\u0434\u0443 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435\u043c \u0438 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u043c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u043c. \u0412\u0441\u0451, \u0447\u0442\u043e \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 <code>state<\/code> \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e \u0432 <code>props<\/code> \u0434\u043e\u0447\u0435\u0440\u043d\u0435\u0433\u043e \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430.<\/p>\n<h3>\u0428\u0430\u0433 6: \u0420\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433 \u0433\u043b\u0430\u0432\u043d\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b<\/h3>\n<p>  \u041d\u0430\u0441\u0442\u0430\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u043e\u0442\u0440\u0435\u043d\u0434\u0435\u0440\u0438\u0442\u044c \u043d\u0430\u0448\u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b. \u041d\u043e \u0447\u0442\u043e\u0431\u044b \u044d\u0442\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e, \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u0435\u0434\u0432\u0430\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0432\u0441\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u0437\u0430\u0434\u0430\u0447\u0438. \u041a\u0430\u043a \u0432\u044b \u043f\u043e\u043c\u043d\u0438\u0442\u0435, \u0437\u0430\u0434\u0430\u0447\u0438 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u044e\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 HTTP API. \u041d\u043e \u0443 \u043d\u0430\u0441 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0435\u0441\u0442\u044c <code>TodoAction<\/code>, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043e\u043f\u0438\u0441\u0430\u043d \u043c\u0435\u0442\u043e\u0434 <code>getTasks<\/code>. \u0412 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u043a Flummox <a href=\"https:\/\/github.com\/acdlite\/flummox\/blob\/8b2e546431b30b2defce111e66ff2dd5775bef6a\/docs\/src\/shared\/utils\/performRouteHandlerStaticMethod.js\">\u043e\u043f\u0438\u0441\u0430\u043d<\/a> \u043c\u0435\u0442\u043e\u0434 \u0441 \u0436\u0443\u0442\u043a\u043e-\u0434\u043b\u0438\u043d\u043d\u044b\u043c \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c <code>performRouteHandlerStaticMethod<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0434\u043e\u043b\u0436\u0435\u043d \u0432\u044b\u0437\u0432\u0430\u0442\u044c \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0443 \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043e\u043f\u0438\u0441\u0430\u043d\u043d\u043e\u0433\u043e \u0432\u044b\u0448\u0435 \u043c\u0435\u0442\u043e\u0434\u0430 <code>routerWillRun<\/code>.<\/p>\n<p>  \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0435\u0433\u043e \u0441\u0435\u0431\u0435.<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">utils\/performRouteHandlerStaticMethod.js<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\">export default async function performRouteHandlerStaticMethod(routes, methodName, ...args) {   return Promise.all(routes     .map(route =&gt; route.handler[methodName])     .filter(method =&gt; typeof method === 'function')     .map(method =&gt; method(...args))   ); } <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0415\u0433\u043e \u043d\u0443\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432 \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u0443\u044e \u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u0443\u044e \u0447\u0430\u0441\u0442\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<pre><code class=\"javascript\">import performRouteHandlerStaticMethod from '..\/utils\/performRouteHandlerStaticMethod';  await performRouteHandlerStaticMethod(state.routes, 'routerWillRun', {state, flux}); <\/code><\/pre>\n<p>  \u041a\u0430\u043a \u044d\u0442\u043e \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c <a href=\"https:\/\/github.com\/asdf404\/flummox-isomorphic-todo\/blob\/2e67af1da2ebe455cb3d25406398f1fdac921674\/server\/app.js#L54\">\u0437\u0434\u0435\u0441\u044c<\/a> \u0438 <a href=\"https:\/\/github.com\/asdf404\/flummox-isomorphic-todo\/blob\/2e67af1da2ebe455cb3d25406398f1fdac921674\/client\/app.js#L20\">\u0437\u0434\u0435\u0441\u044c<\/a>.<\/p>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u044d\u0442\u043e\u0433\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0437\u0432\u0430\u043d \u043c\u0435\u0442\u043e\u0434 <code>routerWillRun<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 Store \u0438 \u043e\u043d\u0438 \u043e\u0442\u043e\u0431\u0440\u0430\u0437\u044f\u0442\u0441\u044f \u0432 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0435.<\/p>\n<h3>\u0428\u0430\u0433 7: \u0421\u0431\u043e\u0440\u043a\u0430 \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u043e\u0439 \u0447\u0430\u0441\u0442\u0438<\/h3>\n<p>  \u041c\u044b \u043d\u0435 \u0437\u0440\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b\u0438 <code>webpack<\/code>. \u041e\u043d \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u043d\u0430\u043c \u0441\u043e\u0431\u0440\u0430\u0442\u044c \u043d\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u043d\u0430 \u043a\u043b\u0438\u0435\u043d\u0442\u0435. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0435\u0433\u043e \u0441\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0443\u0435\u043c.<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">webpack.config.js<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\">var path = require('path'); var webpack = require('webpack');  var DEBUG = process.env.NODE_ENV !== 'production';  var plugins = [     new webpack.optimize.OccurenceOrderPlugin() ];  if (!DEBUG) {     plugins.push(         new webpack.optimize.UglifyJsPlugin()     ); }  module.exports = {     cache: DEBUG,     debug: DEBUG,     target: 'web',     devtool: DEBUG ? '#inline-source-map' : false,     entry: {         client: ['.\/client\/app.js']     },     output: {         path: path.resolve('public\/js'),         publicPath: '\/',         filename: 'bundle.js',         pathinfo: false     },     module: {         loaders: [             {                 test: \/\\.js\/,                 loaders: ['transform?brfs', 'babel-loader?stage=0']             },             {                 test: \/\\.json$\/,                 loaders: ['json-loader']             }         ]     },     plugins: plugins,     resolve: {         extensions: ['', '.js', '.json', '.jsx']     } }; <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0421\u043e\u0431\u0438\u0440\u0430\u0442\u044c\u0441\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0431\u0443\u0434\u0435\u0442 \u0432 \u0444\u0430\u0439\u043b <code>bundle.js<\/code>, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0435\u0433\u043e \u043d\u0430\u0434\u043e \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u043d\u0430 \u043a\u043b\u0438\u0435\u043d\u0442\u0435:<\/p>\n<pre><code class=\"html\">&lt;script type=&quot;text\/javascript&quot; src=&quot;\/js\/bundle.js&quot;&gt;&lt;\/script&gt; <\/code><\/pre>\n<p>  \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u0434\u043b\u044f \u0441\u0431\u043e\u0440\u043a\u0438 \u0432 <code>package.json<\/code>:<\/p>\n<pre><code class=\"javascript\">&quot;scripts&quot;: {   &quot;build&quot;: &quot;webpack&quot; } <\/code><\/pre>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0441\u0431\u043e\u0440\u043a\u0443:<\/p>\n<pre><code class=\"bash\">$ npm run build <\/code><\/pre>\n<p>  \u0421\u043f\u0443\u0441\u0442\u044f \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u043f\u043e\u044f\u0432\u0438\u0442\u0441\u044f \u0444\u0430\u0439\u043b <code>\/public\/js\/bundle.js<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0435\u0439 \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<h3>\u0428\u0430\u0433 8: \u041f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0447\u0442\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c<\/h3>\n<p>  \u041c\u044b \u0442\u043e\u043b\u044c\u043a\u043e \u0447\u0442\u043e \u0441\u043e\u0437\u0434\u0430\u043b\u0438 \u0438\u0437\u043e\u043c\u043e\u0440\u0444\u043d\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435. \u0422\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u0435\u043c \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0435\u0433\u043e <code>npm start<\/code> \u0438 <a href=\"http:\/\/localhost:3000\/\">\u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c<\/a> \u0447\u0442\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c.<\/p>\n<h3>\u041f\u043e\u0441\u043b\u0435\u0441\u043b\u043e\u0432\u0438\u0435<\/h3>\n<p>  \u042f \u0441\u0442\u0430\u0440\u0430\u043b\u0441\u044f \u0434\u043e\u043d\u0435\u0441\u0442\u0438 \u0441\u0432\u043e\u0438 \u043c\u044b\u0441\u043b\u0438 \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u043f\u043e\u043d\u044f\u0442\u043d\u043e, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u0435\u0449\u0438 \u0441\u0438\u043b\u044c\u043d\u043e \u0443\u043f\u0440\u043e\u0449\u0435\u043d\u044b \u0438 \u0441\u0434\u0435\u043b\u0430\u043d\u044b \u043d\u0435 \u0441\u043e\u0432\u0441\u0435\u043c \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e. \u0422\u0430\u043a\u0436\u0435, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0437\u0430\u043f\u0443\u0442\u044b\u0432\u0430\u0442\u044c \u043a\u043e\u0434, \u0432 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043c\u0435\u0441\u0442\u0430\u0445 \u043d\u0435\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u043e\u043a \u043d\u0430 \u043e\u0448\u0438\u0431\u043a\u0438.<\/p>\n<p>  \u0422\u0430\u043a\u0436\u0435 \u0445\u043e\u0447\u0435\u0442\u0441\u044f \u0432\u044b\u0440\u0430\u0437\u0438\u0442\u044c \u0431\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u043d\u043e\u0441\u0442\u044c <a href=\"https:\/\/twitter.com\/ikr\">\u0418\u0432\u0430\u043d\u0443 \u041a\u0440\u0435\u0447\u0435\u0442\u043e\u0432\u0443<\/a> \u0437\u0430 \u0432\u044b\u0447\u0438\u0442\u043a\u0443 \u0447\u0435\u0440\u043d\u043e\u0432\u0438\u043a\u0430 \u0438 \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0430\u0446\u0438\u0438 \u043f\u043e \u0443\u043b\u0443\u0447\u0448\u0435\u043d\u0438\u044e \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0430 \u043a\u043e\u0434\u0430.<\/p>\n<h3>\u041f\u043e\u043b\u0435\u0437\u043d\u043e\u0435 \u0447\u0442\u0435\u043d\u0438\u0435:<\/h3>\n<p>  <\/p>\n<ul>\n<li><a href=\"http:\/\/nerds.airbnb.com\/isomorphic-javascript-future-web-apps\/\">Isomorphic JavaScript: The Future of Web Apps<\/a>;<\/li>\n<li><a href=\"http:\/\/acdlite.github.io\/flummox\/docs\/guides\/quick-start\">Flummox: Quick start<\/a>;<\/li>\n<li><a href=\"https:\/\/medium.com\/@dan_abramov\/smart-and-dumb-components-7ca2f9a7c7d0\">Smart and Dumb Components<\/a>;<\/li>\n<li><a href=\"http:\/\/jakearchibald.com\/2014\/es7-async-functions\/\">ES7 async functions<\/a>;<\/li>\n<\/ul>\n<p>  Happy coding! \t\t\t<\/p>\n<div class=\"clear\"><\/div>\n<p> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"http:\/\/habrahabr.ru\/post\/256979\/\"> http:\/\/habrahabr.ru\/post\/256979\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p> \t\t\t\u0421\u0435\u0433\u043e\u0434\u043d\u044f \u044f \u0445\u043e\u0447\u0443 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c, \u043a\u0430\u043a \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f React, Flummox \u0438 Express, \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u043e\u0435 \u0438\u0437\u043e\u043c\u043e\u0440\u0444\u043d\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435.<\/p>\n<p>  \u0418\u0434\u0435\u044f \u0438\u0437\u043e\u043c\u043e\u0440\u0444\u043d\u043e\u0441\u0442\u0438 \u0434\u0430\u0432\u043d\u043e \u0432\u0438\u0442\u0430\u043b\u0430 \u0432 \u0432\u043e\u0437\u0434\u0443\u0445\u0435, \u043d\u043e \u043d\u0438\u043a\u0442\u043e \u043d\u0435 \u0437\u043d\u0430\u043b \u044d\u0442\u043e\u0433\u043e \u0441\u043b\u043e\u0432\u0430, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0438\u0447\u0435\u0433\u043e \u043e\u0441\u043e\u0431\u043e \u043d\u0435 \u043c\u0435\u043d\u044f\u043b\u043e\u0441\u044c, \u043f\u043e\u043a\u0430 \u043d\u0435 <a href=\"http:\/\/nerds.airbnb.com\/isomorphic-javascript-future-web-apps\/\">\u043f\u0440\u0438\u0448\u0435\u043b airbnb<\/a>.<\/p>\n<p>  \u0417\u0430 \u043f\u043e\u043b\u0433\u043e\u0434\u0430 \u0434\u043e \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u044f\u0432\u0438\u043b\u0441\u044f React, \u043f\u043e\u0437\u0436\u0435 \u043f\u043e\u044f\u0432\u0438\u043b\u0441\u044f Flux \u0438 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u0435\u0433\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0439, \u043e\u0434\u043d\u0430 \u043d\u0435 \u0445\u0443\u0436\u0435 \u0434\u0440\u0443\u0433\u043e\u0439. \u041d\u043e \u0432\u0441\u0435 \u044d\u0442\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043e\u0440\u0438\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043b\u0438\u0441\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430 \u0440\u0430\u0431\u043e\u0442\u0443 \u043d\u0430 \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u043e\u0439 \u0441\u0442\u043e\u0440\u043e\u043d\u0435, \u043e\u043d\u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u043b\u0438 \u0447\u0435\u0440\u0435\u0437 \u0441\u0438\u043d\u0433\u043b\u0442\u043e\u043d\u044b \u0438, \u0437\u0430\u0447\u0430\u0441\u0442\u0443\u044e, \u0438\u0445 \u043d\u0435\u043b\u044c\u0437\u044f \u0431\u044b\u043b\u043e \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435. \u042f \u0443\u0441\u043f\u0435\u043b \u043f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e, \u043d\u043e \u043d\u0438 \u043e\u0434\u043d\u0430 \u043c\u043d\u0435 \u043d\u0435 \u043f\u043e\u043d\u0440\u0430\u0432\u0438\u043b\u0430\u0441\u044c. \u041f\u043e\u043a\u0430 \u0434\u0432\u0430 \u043c\u0435\u0441\u044f\u0446\u0430 \u043d\u0430\u0437\u0430\u0434 \u044f \u043d\u0435 \u043d\u0430\u0442\u043a\u043d\u0443\u043b\u0441\u044f \u043d\u0430 Flummox. \u041a\u0430\u043a \u0437\u0430\u044f\u0432\u043b\u044f\u0435\u0442 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a, Flummox \u0441\u043e\u0437\u0434\u0430\u043d \u043a\u0430\u043a \u0440\u0430\u0437 \u0434\u043b\u044f \u0438\u0437\u043e\u043c\u043e\u0440\u0444\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u043e\u043d \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0441\u0438\u043d\u0433\u043b\u0442\u043e\u043d\u044b, \u043f\u0440\u0438\u0441\u0443\u0449\u0438\u0435 \u0434\u0440\u0443\u0433\u0438\u043c \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f\u043c, \u0438 \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442 \u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438.<\/p>\n<p>  \u041e\u0436\u0438\u0434\u0430\u0435\u0442\u0441\u044f, \u0447\u0442\u043e \u0432\u044b \u0438\u043c\u0435\u0435\u0442\u0435 \u043e\u043f\u044b\u0442 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 React \u0438 \u0441\u043b\u044b\u0448\u0430\u043b\u0438 \u043f\u0440\u043e Flux. \u0418\u0442\u0430\u043a, \u043f\u043e\u0435\u0445\u0430\u043b\u0438\u2026<br \/>  \u0417\u0430\u0431\u0440\u0430\u0442\u044c \u0433\u043e\u0442\u043e\u0432\u044b\u0439 \u043a\u043e\u0434 \u043c\u043e\u0436\u043d\u043e <a href=\"https:\/\/github.com\/asdf404\/flummox-isomorphic-todo\">\u0442\u0443\u0442<\/a>.  <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-256315","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/256315","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=256315"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/256315\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=256315"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=256315"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=256315"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}