{"id":388043,"date":"2024-06-29T07:41:53","date_gmt":"2024-06-29T07:41:53","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=388043"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=388043","title":{"rendered":"<span>Redux Vs Vuex. \u0427\u0430\u0441\u0442\u044c 2<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w780q1\/webt\/py\/cs\/xn\/pycsxnw-4_owrob4sqtc9gqyabi.jpeg\" data-src=\"https:\/\/habrastorage.org\/webt\/py\/cs\/xn\/pycsxnw-4_owrob4sqtc9gqyabi.jpeg\" data-blurred=\"true\"\/>  <\/p>\n<p>  \u041f\u0440\u0438\u0432\u0435\u0442, \u0434\u0440\u0443\u0437\u044c\u044f!<\/p>\n<p>  <\/p>\n<p>\u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u0432\u0430\u0448\u0435\u043c\u0443 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u044e \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0433\u043e \u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u044f, \u043f\u043e\u0441\u0432\u044f\u0449\u0435\u043d\u043d\u043e\u0433\u043e \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044e <a href=\"https:\/\/redux.js.org\/\"><code>Redux<\/code><\/a> \u0438 <a href=\"https:\/\/next.vuex.vuejs.org\/\"><code>Vuex<\/code><\/a>. \u042d\u0442\u043e \u0432\u0442\u043e\u0440\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u0441\u0442\u0430\u0442\u044c\u0438, \u0432\u043e\u0442 <a href=\"https:\/\/habr.com\/ru\/company\/timeweb\/blog\/566682\/\">\u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043f\u0435\u0440\u0432\u0443\u044e<\/a>.<\/p>\n<p>  <\/p>\n<h2 id=\"vvedenie\">\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435<\/h2>\n<p>  <\/p>\n<p><code>Redux<\/code> \u0438 <code>Vuex<\/code> \u2014 \u044d\u0442\u043e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0445 \u043d\u0430 <a href=\"https:\/\/ru.reactjs.org\/\"><code>React<\/code><\/a> \u0438 <a href=\"https:\/\/vuejs.org\/\"><code>Vue<\/code><\/a>, \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e. \u041a\u0430\u0436\u0434\u0430\u044f \u0438\u0437 \u043d\u0438\u0445 \u043f\u043e-\u0441\u0432\u043e\u0435\u043c\u0443 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0443 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0445 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u0432, \u0438\u0437\u0432\u0435\u0441\u0442\u043d\u0443\u044e \u043f\u043e\u0434 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c <a href=\"https:\/\/facebook.github.io\/flux\/\"><code>Flux<\/code><\/a>.<\/p>\n<p><a name=\"habracut\"><\/a>  <\/p>\n<p><em>\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435<\/em>: Flux-\u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0430 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 <em>\u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u044b\u043c \u0438\u043b\u0438 \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u043c<\/em> (global, shared) \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c, \u0442.\u0435. \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0434\u0432\u0443\u043c\u044f \u0438 \u0431\u043e\u043b\u0435\u0435 <em>\u0430\u0432\u0442\u043e\u043d\u043e\u043c\u043d\u044b\u043c\u0438<\/em> \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430\u043c\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0410\u0432\u0442\u043e\u043d\u043e\u043c\u043d\u044b\u043c\u0438 \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b, \u043c\u0435\u0436\u0434\u0443 \u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u043d\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u043e\u0442\u043d\u043e\u0448\u0435\u043d\u0438\u0439 \u0438\u043b\u0438 \u0441\u0432\u044f\u0437\u0438 &#171;\u043f\u0440\u0435\u0434\u043e\u043a-\u043f\u043e\u0442\u043e\u043c\u043e\u043a&#187; \u0438\u043b\u0438 &#171;\u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c-\u0440\u0435\u0431\u0435\u043d\u043e\u043a&#187;, \u0442.\u0435. \u044d\u0442\u043e \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0438\u0437 \u0440\u0430\u0437\u043d\u044b\u0445 \u043f\u043e\u0434\u0434\u0435\u0440\u0435\u0432\u044c\u0435\u0432 \u0434\u0435\u0440\u0435\u0432\u0430 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432. \u0421\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043e\u0434\u043d\u0438\u043c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u043c \u0438\u043b\u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442\u0441\u044f \u043e\u0442 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0433\u043e \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u043c \u0438 \u043e\u0431\u0440\u0430\u0442\u043d\u043e (\u0432 \u043f\u0440\u0435\u0434\u0435\u043b\u0430\u0445 \u043e\u0434\u043d\u043e\u0433\u043e \u043f\u043e\u0434\u0434\u0435\u0440\u0435\u0432\u0430), \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u043c (local), \u043e\u043d\u043e \u0434\u043e\u043b\u0436\u043d\u043e \u0445\u0440\u0430\u043d\u0438\u0442\u044c\u0441\u044f \u0438 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u043c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u043c. \u0420\u0430\u0437\u0443\u043c\u0435\u0435\u0442\u0441\u044f, \u044d\u0442\u043e \u043d\u0435 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0441\u044f \u043a \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u043c\u0443 (root) \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0443.<\/p>\n<p>  <\/p>\n<p>\u0421\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0435 \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0438\u043b\u043b\u044e\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c (\u0434\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u0430 \u043f\u043e\u0441\u0432\u044f\u0449\u0435\u043d\u0430 \u043a\u043e\u043b\u043b\u043e\u043a\u0430\u0446\u0438\u0438, \u0438\u043b\u0438 \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u043d\u043e\u043c\u0443 \u0440\u0430\u0437\u043c\u0435\u0449\u0435\u043d\u0438\u044e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439, \u043d\u043e \u0441\u0443\u0442\u0438 \u0434\u0435\u043b\u0430 \u044d\u0442\u043e \u043d\u0435 \u043c\u0435\u043d\u044f\u0435\u0442):<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w780q1\/webt\/gz\/_o\/yx\/gz_oyx9xhm_7wvpydh1uk1wc3wy.jpeg\" data-src=\"https:\/\/habrastorage.org\/webt\/gz\/_o\/yx\/gz_oyx9xhm_7wvpydh1uk1wc3wy.jpeg\" data-blurred=\"true\"\/>  <\/p>\n<p>\u0410\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 <code>Flux<\/code> (\u0432 <code>Redux<\/code>) \u043f\u0440\u0435\u0434\u043f\u043e\u043b\u0430\u0433\u0430\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435:<\/p>\n<p>  <\/p>\n<ul>\n<li>\u043d\u0430\u043b\u0438\u0447\u0438\u0435 \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0433\u043e \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430 \u0438\u0441\u0442\u0438\u043d\u044b \u0438\u043b\u0438 \u043c\u0435\u0441\u0442\u0430 \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u2014 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430 (store);<\/li>\n<li>\u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0438\u0437\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <a href=\"https:\/\/ru.wikipedia.org\/wiki\/%D0%A7%D0%B8%D1%81%D1%82%D0%BE%D1%82%D0%B0_%D1%84%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D0%B8\">\u0447\u0438\u0441\u0442\u044b\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439<\/a> \u2014 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0439 (actions);<\/li>\n<li>\u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u0438\u0437\u043c\u0435\u043d\u044f\u044e\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043d\u0435 \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e, \u0430 \u0447\u0435\u0440\u0435\u0437 \u0440\u0435\u0434\u0443\u043a\u0442\u043e\u0440 (reducer), \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043e\u0434\u0438\u0444\u0438\u0446\u0438\u0440\u0443\u0435\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0442\u0438\u043f\u0430 (type) \u0438 \u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0439 (\u043d\u0435\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0439) \u043f\u043e\u043b\u0435\u0437\u043d\u043e\u0439 \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0438 (payload) \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438;<\/li>\n<li>\u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0432 \u0440\u0435\u0434\u0443\u043a\u0442\u043e\u0440 \u0438\u0437 \u0441\u043b\u043e\u044f \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f (view), \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430, \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0434\u0438\u0441\u043f\u0435\u0442\u0447\u0435\u0440\u0430 (dispatcher);<\/li>\n<li>\u0432\u044b\u0431\u043e\u0440\u043a\u0430 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0438\u043b\u0438 \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0441\u0435\u043b\u0435\u043a\u0442\u043e\u0440\u043e\u0432 (selectors). \u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0434\u0443\u043c\u0430\u0442\u044c \u043e \u0441\u0435\u043b\u0435\u043a\u0442\u043e\u0440\u0430\u0445 \u043a\u0430\u043a \u043e\u0431 \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f\u0445 <code>SELECT<\/code> \u0438\u0437 \u044f\u0437\u044b\u043a\u0430 <code>SQL<\/code><\/li>\n<li>\u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438, \u0442\u0430\u043a\u0438\u0435 \u043a\u0430\u043a HTTP- \u0438\u043b\u0438 AJAX-\u0437\u0430\u043f\u0440\u043e\u0441\u044b, \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0442\u0441\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 (thunks).<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0415\u0441\u043b\u0438 \u0432\u0430\u0441 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u043e\u0434, \u0442\u043e \u0432\u043e\u0442 <a href=\"https:\/\/github.com\/harryheman\/redux-vs-vuex\">\u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439<\/a>.<\/p>\n<p>  <\/p>\n<p>\u0414\u0435\u043c\u043e React-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c <a href=\"https:\/\/codesandbox.io\/s\/redux-todo-n618x\">\u0437\u0434\u0435\u0441\u044c<\/a>, \u0430 Vue-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u2014 <a href=\"https:\/\/codesandbox.io\/s\/vuex-todo-rsfj5\">\u0437\u0434\u0435\u0441\u044c<\/a>.<\/p>\n<p>  <\/p>\n<p>\u0412\u044b \u0433\u043e\u0442\u043e\u0432\u044b? \u0422\u043e\u0433\u0434\u0430 \u0432\u043f\u0435\u0440\u0435\u0434!<\/p>\n<p>  <\/p>\n<h2 id=\"vuex\">Vuex<\/h2>\n<p>  <\/p>\n<p><a href=\"https:\/\/next.vuex.vuejs.org\/\"><code>Vuex<\/code><\/a> \u2014 \u044d\u0442\u043e \u043f\u0430\u0442\u0442\u0435\u0440\u043d \/ \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c, \u0432\u0434\u043e\u0445\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u0430\u044f <a href=\"https:\/\/facebook.github.io\/flux\/\"><code>Flux<\/code><\/a>, <a href=\"https:\/\/redux.js.org\/\"><code>Redux<\/code><\/a> \u0438 <a href=\"https:\/\/guide.elm-lang.org\/\"><code>Elm<\/code><\/a>.<\/p>\n<p>  <\/p>\n<p>\u041a\u0430\u043a \u0438 \u0432 <code>Redux<\/code>, \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u043c \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u043c \u0438\u0441\u0442\u0438\u043d\u044b \u0438\u043b\u0438 \u043c\u0435\u0441\u0442\u043e\u043c \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0432 <code>Vuex<\/code> \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 (store). \u0421\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0442\u0430\u043a\u0436\u0435 \u043d\u0435 \u0438\u0437\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e. \u0412\u043c\u0435\u0441\u0442\u043e \u044d\u0442\u043e\u0433\u043e \u0441\u043b\u043e\u0439 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f (view) \u2014 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u2014 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 (actions), \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0433\u0443\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c (dispatch) \u0434\u0440\u0443\u0433\u0438\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u0438\u043b\u0438 \u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u0442\u044c (commit) \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043c\u0443\u0442\u0430\u0446\u0438\u0439 (mutations). \u041c\u0443\u0442\u0430\u0446\u0438\u0438 \u0442\u0430\u043a\u0436\u0435 \u043c\u043e\u0433\u0443\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c\u0441\u044f \u0438\u0437 \u0441\u043b\u043e\u044f \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e. \u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0435 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043c\u0435\u0436\u0434\u0443 \u043c\u0443\u0442\u0430\u0446\u0438\u044f\u043c\u0438 \u0438 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044f\u043c\u0438 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u043c\u0443\u0442\u0430\u0446\u0438\u0438 \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u0442\u044c \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c\u0438, \u0430 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438, \u043f\u043e \u0441\u0443\u0442\u0438, \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u044b \u0434\u043b\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0439 \u043b\u043e\u0433\u0438\u043a\u0438 \u0441 \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u043c \u043c\u0443\u0442\u0430\u0446\u0438\u0439. \u041e\u0434\u043d\u0430\u043a\u043e \u0437\u0430\u0447\u0430\u0441\u0442\u0443\u044e \u043c\u0443\u0442\u0430\u0446\u0438\u0438 \u0438 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u0434\u0443\u0431\u043b\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u0438 \u0441\u043b\u043e\u0439 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0443\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0441 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044f\u043c\u0438. \u0414\u043b\u044f \u0438\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u0438\u044f \u0447\u0430\u0441\u0442\u0438 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0432 <code>Vuex<\/code> \u0432\u043c\u0435\u0441\u0442\u043e \u0441\u0435\u043b\u0435\u043a\u0442\u043e\u0440\u043e\u0432 (selectors) \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0433\u0435\u0442\u0442\u0435\u0440\u044b (getters).<\/p>\n<p>  <\/p>\n<p>\u042d\u0442\u043e \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0442\u0430\u043a:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/ob\/4f\/3m\/ob4f3mwptfscqsdfbrejw7isj64.png\" data-src=\"https:\/\/habrastorage.org\/webt\/ob\/4f\/3m\/ob4f3mwptfscqsdfbrejw7isj64.png\"\/>  <\/p>\n<p><strong>API<\/strong><\/p>\n<p>  <\/p>\n<p><em>\u0425\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435<\/em><\/p>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043c\u0435\u0442\u043e\u0434 <code>createStore()<\/code>, \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442\u0441\u044f \u043e\u0431\u044a\u0435\u043a\u0442 \u0441\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c\u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u043c\u0438 (\u0438\u0437 \u0442\u0435\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c):<\/p>\n<p>  <\/p>\n<ul>\n<li><code>state: object | function<\/code>\u2014 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f<\/li>\n<li><code>mutations: { [string]: function }<\/code> \u2014 \u043e\u0431\u044a\u0435\u043a\u0442 \u0441 \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u043c\u0438 \u0434\u043b\u044f \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0439 \u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f. \u041a\u0430\u0436\u0434\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0442\u0435\u043a\u0443\u0449\u0435\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 (<code>state<\/code>), \u0430 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0432\u0442\u043e\u0440\u043e\u0433\u043e \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430 \u2014 \u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u0443\u044e \u043f\u043e\u043b\u0435\u0437\u043d\u0443\u044e \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0443 (<code>payload<\/code>)<\/li>\n<li><code>actions: { [string]: function }<\/code> \u2014 \u043e\u0431\u044a\u0435\u043a\u0442, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0438\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0445 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0439 \u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043c\u0443\u0442\u0430\u0446\u0438\u0439 \u0434\u043b\u044f \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f. \u041a\u0430\u0436\u0434\u0430\u044f \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044f \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0432\u0442\u043e\u0440\u043e\u0433\u043e \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430, \u043a\u0430\u043a \u0438 \u043c\u0443\u0442\u0430\u0446\u0438\u0438, \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u0443\u044e \u043f\u043e\u043b\u0435\u0437\u043d\u0443\u044e \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0443 (<code>payload<\/code>), \u0430 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430 \u2014 \u043e\u0431\u044a\u0435\u043a\u0442 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430 (<code>context<\/code>) \u0441\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c\u0438 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430\u043c\u0438:<br \/> \n<ul>\n<li><code>state<\/code> \u2014 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435<\/li>\n<li><code>commit<\/code> \u2014 \u043c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043c\u0443\u0442\u0430\u0446\u0438\u0438<\/li>\n<li><code>dispatch<\/code> \u2014 \u043c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0434\u0440\u0443\u0433\u043e\u0439 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438<\/li>\n<li><code>getters<\/code> \u2014 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0433\u0435\u0442\u0442\u0435\u0440\u043e\u0432<\/li>\n<\/ul>\n<\/li>\n<li><code>getters: { [string]: function }<\/code> \u2014 \u0433\u0435\u0442\u0442\u0435\u0440\u044b \u0434\u043b\u044f \u0438\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u0438\u044f \u0447\u0430\u0441\u0442\u0438 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0438\u043b\u0438 \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445. \u041a\u0430\u0436\u0434\u044b\u0439 \u0433\u0435\u0442\u0442\u0435\u0440 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 (<code>state<\/code>) \u0438 \u0433\u0435\u0442\u0442\u0435\u0440\u044b (<code>getters<\/code>)<\/li>\n<\/ul>\n<p>  <\/p>\n<pre><code class=\"javascript\">import { createStore } from 'vuex'  const store = createStore({  state() {    return {      count: 0    }  }  mutations: {    ['SET_COUNT'](state, payload) {      state.count = payload.count    },    ['INCREMENT'](state){      state.count++    },    ['DECREMENT'](state){      state.count--    },    ['INCREMENT_BY_AMOUNT'](state, payload) {      state.count += payload.amount    }  },  actions: {    increment({ commit }) {      commit('INCREMENT')    },    decrement({ commit }) {      commit('DECREMENT')    },    incrementByAmount({ commit }, payload) {      commit('INCREMENT_BY_AMOUNT', payload)    },    setCount({ commit }, payload) {      commit('SET_COUNT', payload)    },    setCountAsync({ dispatch }) {      const timerId = setTimeout(() => {        dispatch(setCount(10))        clearTimeout(timerId)      }, 1000)    }  } })<\/code><\/pre>\n<p>  <\/p>\n<p><em>\u042d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430<\/em><\/p>\n<p>  <\/p>\n<p>\u0414\u043e\u0441\u0442\u0443\u043f \u043a \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0443 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430 \u0432 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0435 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>this.$store<\/code>.<\/p>\n<p>  <\/p>\n<p>\u0421\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0430 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430:<\/p>\n<p>  <\/p>\n<ul>\n<li><code>state<\/code> \u2014 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435;<\/li>\n<li><code>getters<\/code> \u2014 \u0433\u0435\u0442\u0442\u0435\u0440\u044b.<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u041c\u0435\u0442\u043e\u0434\u044b \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0430 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430:<\/p>\n<p>  <\/p>\n<ul>\n<li><code>commit<\/code> \u2014 \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043c\u0443\u0442\u0430\u0446\u0438\u0438;<\/li>\n<li><code>dispatch<\/code> \u2014 \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438;<\/li>\n<li><code>replaceState<\/code> \u2014 \u0434\u043b\u044f \u0437\u0430\u043c\u0435\u043d\u044b \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f; \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u0433\u0438\u0434\u0440\u0430\u0442\u0430\u0446\u0438\u0438 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f;<\/li>\n<li><code>watch (function, callback)<\/code>\u2014 \u0434\u043b\u044f \u043d\u0430\u0431\u043b\u044e\u0434\u0435\u043d\u0438\u044f \u0437\u0430 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u043c, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u044b\u043c <code>function<\/code>, \u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u043c <code>callback<\/code> \u043f\u0440\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u044d\u0442\u043e\u0433\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f;<\/li>\n<li><code>subscribe (handler, options)<\/code> \u2014 \u0434\u043b\u044f \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0438 \u043d\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430. \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a (<code>handler<\/code>) \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u043c\u0443\u0442\u0430\u0446\u0438\u044e \u0438 \u043c\u043e\u0434\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0435 \u044d\u0442\u043e\u0439 \u043c\u0443\u0442\u0430\u0446\u0438\u0435\u0439 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0438, \u043f\u043e\u043c\u0438\u043c\u043e \u043f\u0440\u043e\u0447\u0435\u0433\u043e, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043e\u0442\u043f\u0438\u0441\u043a\u0438 \u2014 <code>const unsubsciribe = store.subscribe((mutation, state) => {})<\/code>. \u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u043a\u0430\u0436\u0434\u044b\u0439 \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432 \u043a\u043e\u043d\u0435\u0446 \u0446\u0435\u043f\u043e\u0447\u043a\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432. \u0414\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u0432 \u043d\u0430\u0447\u0430\u043b\u043e \u0446\u0435\u043f\u043e\u0447\u043a\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 <code>prepend<\/code> \u0441\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u043c <code>true<\/code> \u2014 <code>store.subscribe(handler, { prepend: true })<\/code><\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0421\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u0434\u043b\u044f \u043e\u0441\u043e\u0431\u044b\u0445 \u0441\u043b\u0443\u0447\u0430\u0435\u0432.<\/p>\n<p>  <\/p>\n<p><em>\u0423\u0442\u0438\u043b\u0438\u0442\u044b \u0434\u043b\u044f \u043f\u0440\u0438\u0432\u044f\u0437\u043a\u0438 (binding)<\/em><\/p>\n<p>  <\/p>\n<ul>\n<li><code>mapState<\/code> \u2014 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u043c\u044b\u0445 \u0441\u0432\u043e\u0439\u0441\u0442\u0432 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0449\u0438\u0445 \u0447\u0430\u0441\u0442\u044c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f;<\/li>\n<li><code>mapGetters<\/code> \u2014 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u043c\u044b\u0445 \u0441\u0432\u043e\u0439\u0441\u0442\u0432 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0449\u0438\u0445 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0433\u0435\u0442\u0442\u0435\u0440\u043e\u0432;<\/li>\n<li><code>mapActions<\/code> \u2014 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430, \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u0445 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438;<\/li>\n<li><code>mapMutations<\/code> \u2014 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043c\u0435\u0442\u043e\u0434\u043e\u0432, \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u044e\u0449\u0438\u0445 \u043c\u0443\u0442\u0430\u0446\u0438\u0438.<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0418 \u044d\u0442\u043e \u0432\u0441\u0435, \u0447\u0442\u043e \u0432\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0437\u043d\u0430\u0442\u044c \u043e <code>Vuex<\/code>, \u043d\u0443, \u043f\u043e\u0447\u0442\u0438, \u043d\u0435 \u0441\u0447\u0438\u0442\u0430\u044f \u043f\u0440\u043e\u0434\u0432\u0438\u043d\u0443\u0442\u044b\u0445 \u0442\u0435\u043c, \u0432\u0440\u043e\u0434\u0435 \u043c\u043e\u0434\u0443\u043b\u0435\u0439 \u0438\u043b\u0438 \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432 \u0438\u043c\u0435\u043d. &#171;\u0412\u0441\u0435? \u2014 \u0441\u043f\u0440\u043e\u0441\u0438\u0442\u0435 \u0432\u044b. \u2014 \u041d\u043e \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u0438\u044e <code>Redux Toolkit<\/code> \u0431\u044b\u043b\u0430 \u043f\u043e\u0441\u0432\u044f\u0449\u0435\u043d\u0430 \u0446\u0435\u043b\u0430\u044f \u0441\u0442\u0430\u0442\u044c\u044f!&#187; \u0412\u043e\u0442 \u0438\u043c\u0435\u043d\u043d\u043e, \u0434\u0440\u0443\u0437\u044c\u044f, \u0432\u043e\u0442 \u0438\u043c\u0435\u043d\u043d\u043e.<\/p>\n<p>  <\/p>\n<p><strong>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430<\/strong><\/p>\n<p>  <\/p>\n<p>\u0423\u0447\u0438\u0442\u044b\u0432\u0430\u044f, \u0447\u0442\u043e \u043c\u044b \u0441\u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043b\u0438 \u043d\u0430\u0448\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u0432 \u043f\u0435\u0440\u0432\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u0441\u0442\u0430\u0442\u044c\u0438, \u043c\u043e\u0436\u043d\u043e \u0441\u0440\u0430\u0437\u0443 \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0430\u0442\u044c \u043a \u0435\u0433\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>Vuex<\/code>. \u041f\u043e\u0440\u0430\u0437\u043c\u044b\u0441\u043b\u0438\u0432, \u044f \u043f\u0440\u0438\u0448\u0435\u043b \u043a \u0432\u044b\u0432\u043e\u0434\u0443, \u0447\u0442\u043e \u0438\u043d\u0434\u0438\u043a\u0430\u0442\u043e\u0440 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 (\u0441\u0442\u0430\u0442\u0443\u0441) \u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 (\u043e\u0431 \u0443\u0441\u043f\u0435\u0445\u0435 \u0438\u043b\u0438 \u043f\u0440\u043e\u0432\u0430\u043b\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0439) \u0434\u043e\u043b\u0436\u043d\u044b \u043f\u0440\u0438\u043d\u0430\u0434\u043b\u0435\u0436\u0430\u0442\u044c \u0432\u0441\u0435\u043c\u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044e, \u0430 \u043d\u0435 \u0447\u0430\u0441\u0442\u0438 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0434\u043b\u044f \u0437\u0430\u0434\u0430\u0447, \u043a\u0430\u043a \u044d\u0442\u043e \u0431\u044b\u043b\u043e \u0432 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 <code>Redux<\/code>. \u0422\u0430\u043a\u0436\u0435 \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043e\u0442\u043b\u0438\u0447\u0430\u0435\u0442\u0441\u044f \u043b\u043e\u0433\u0438\u043a\u0430 \u0432\u044b\u0437\u043e\u0432\u0430 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u0434\u043b\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0438\u0441\u043a\u0443\u0441\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0439 \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0438 \u043f\u0435\u0440\u0435\u0434 \u043e\u0447\u0438\u0441\u0442\u043a\u043e\u0439 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">import { createStore } from 'vuex' \/\/ \u0423\u0442\u0438\u043b\u0438\u0442\u0430 \u0434\u043b\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f HTTP-\u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 import axios from 'axios'  \/\/ \u0410\u0434\u0440\u0435\u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 const SERVER_URL = 'http:\/\/localhost:5000\/todos'  \/\/ \u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044f - \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0437\u0430\u0434\u0430\u0447 \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 const getTodos = async () => {  try {    const { data: todos } = await axios(SERVER_URL)    \/\/ \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0437\u0430\u0434\u0430\u0447\u0438 \u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043e\u0431 \u0443\u0441\u043f\u0435\u0445\u0435    return {      todos,      message: { type: 'success', text: 'Todos has been loaded' }    }  } catch (err) {    console.error(err.toJSON())    \/\/ \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0435    return {      message: {        type: 'error',        text: 'Something went wrong. Try again later'      }    }  } }  \/\/ \u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044f - \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0437\u0430\u0434\u0430\u0447 \u0432 \u0411\u0414 const postTodos = async (newTodos) => {  try {    \/\/ \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435 - \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u0437\u0430\u0434\u0430\u0447\u0438    const { data: existingTodos } = await axios(SERVER_URL)     \/\/ \u043f\u0435\u0440\u0435\u0431\u0438\u0440\u0430\u0435\u043c \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u0437\u0430\u0434\u0430\u0447\u0438    for (const todo of existingTodos) {      \/\/ \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c `URL` \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0437\u0430\u0434\u0430\u0447\u0438      const todoUrl = `${SERVER_URL}\/${todo.id}`       \/\/ \u043f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u043d\u0430\u0439\u0442\u0438 \u043e\u0431\u0449\u0443\u044e \u0437\u0430\u0434\u0430\u0447\u0443      const commonTodo = newTodos.find((_todo) => _todo.id === todo.id)       \/\/ \u0435\u0441\u043b\u0438 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c      if (commonTodo) {        \/\/ \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u043d\u0430\u043b\u0438\u0447\u0438\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439        if (          !Object.entries(commonTodo).every(            ([key, value]) => value === todo[key]          )        ) {          \/\/ \u0435\u0441\u043b\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0435\u0441\u0442\u044c, \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u043c \u0437\u0430\u0434\u0430\u0447\u0443 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435,          \/\/ \u0432 \u043f\u0440\u043e\u0442\u0438\u0432\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u0434\u0435\u043b\u0430\u0435\u043c          await axios.put(todoUrl, commonTodo)        }      } else {        \/\/ \u0435\u0441\u043b\u0438 \u043e\u0431\u0449\u0430\u044f \u0437\u0430\u0434\u0430\u0447\u0430 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442, \u0443\u0434\u0430\u043b\u044f\u0435\u043c \u0437\u0430\u0434\u0430\u0447\u0443 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435        await axios.delete(todoUrl)      }    }     \/\/ \u043f\u0435\u0440\u0435\u0431\u0438\u0440\u0430\u0435\u043c \u043d\u043e\u0432\u044b\u0435 \u0437\u0430\u0434\u0430\u0447\u0438 \u0438 \u0441\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0435\u043c \u0438\u0445 \u0441 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u043c\u0438    for (const todo of newTodos) {      \/\/ \u0435\u0441\u043b\u0438 \u043d\u043e\u0432\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438 \u043d\u0435\u0442 \u0441\u0440\u0435\u0434\u0438 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445      if (!existingTodos.find((_todo) => _todo.id === todo.id)) {        \/\/ \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u0435\u0435 \u0432 \u0411\u0414        await axios.post(SERVER_URL, todo)      }    }    \/\/ \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043e\u0431 \u0443\u0441\u043f\u0435\u0445\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438    return {      type: 'success',      text: 'Todos has been saved'    }  } catch (err) {    console.error(err.toJSON())    \/\/ \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043e \u043f\u0440\u043e\u0432\u0430\u043b\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438    return {      type: 'error',      text: 'Something went wrong. Try again later'    }  } }  \/\/ \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0438 \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 export default createStore({  \/\/ \u041d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435  state: {    \/\/ \u0434\u043b\u044f \u0437\u0430\u0434\u0430\u0447    todos: [],    \/\/ \u0434\u043b\u044f \u0441\u0442\u0430\u0442\u0443\u0441\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f    status: 'idle',    \/\/ \u0434\u043b\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f    message: {},    \/\/ \u0434\u043b\u044f \u0444\u0438\u043b\u044c\u0442\u0440\u0430    filter: 'all'  },  \/\/ \u041c\u0443\u0442\u0430\u0446\u0438\u0438 - \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f \u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f  mutations: {    \/\/ \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0437\u0430\u0434\u0430\u0447    ['SET_TODOS'](state, { todos, message }) {      if (todos) {        state.todos = todos      }      state.message = message      state.status = 'idle'    },    \/\/ \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0441\u0442\u0430\u0442\u0443\u0441\u0430    ['SET_STATUS'](state, status) {      state.status = status    },    \/\/ \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u043e\u0432\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438    ['ADD_TODO'](state, todo) {      state.todos.push(todo)    },    \/\/ \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u0437\u0430\u0434\u0430\u0447\u0438    ['REMOVE_TODO'](state, todo) {      state.todos.splice(state.todos.indexOf(todo), 1)    },    \/\/ \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0437\u0430\u0434\u0430\u0447\u0438    ['UPDATE_TODO'](state, { id, changes }) {      const index = state.todos.findIndex((todo) => todo.id === id)      state.todos.splice(index, 1, { ...state.todos[index], ...changes })    },    \/\/ \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0435 \u0432\u0441\u0435\u0445 \u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0445 \u0437\u0430\u0434\u0430\u0447    ['COMPLETE_TODOS'](state) {      state.todos = state.todos.map((todo) =>        todo.done ? todo : { ...todo, done: !todo.done }      )    },    \/\/ \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u044b\u0445 \u0437\u0430\u0434\u0430\u0447    ['CLEAR_COMPLETED'](state) {      state.todos = state.todos.filter((todo) => !todo.done)    },    \/\/ \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0437\u0430\u0434\u0430\u0447 \u0432 \u0411\u0414    ['SAVE_TODOS'](state, message) {      state.message = message      state.status = 'idle'    },    \/\/ \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0444\u0438\u043b\u044c\u0442\u0440\u0430    ['SET_FILTER'](state, filter) {      state.filter = filter    },    \/\/ \u043e\u0447\u0438\u0441\u0442\u043a\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f    ['CLEAR_MESSAGE'](state) {      state.message = {}    }  },  \/\/ \u041e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 - \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f \u043b\u043e\u0433\u0438\u043a\u0430 \u0438 \u0432\u044b\u0437\u043e\u0432 \u043c\u0443\u0442\u0430\u0446\u0438\u0439  actions: {    \/\/ \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0437\u0430\u0434\u0430\u0447 \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430    fetchTodos({ commit, dispatch, state }) {      state.status = 'loading'      getTodos()        .then((todos) => {          commit('SET_TODOS', todos)        })        .then(() => {          dispatch('giveMeSomeTime')        })    },    \/\/ \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0441\u0442\u0430\u0442\u0443\u0441\u0430    setStatus({ commit }, status) {      commit('SET_STATUS', status)    },    \/\/ \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u043e\u0432\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438    addTodo({ commit }, todo) {      commit('ADD_TODO', todo)    },    \/\/ \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0437\u0430\u0434\u0430\u0447\u0438    updateTodo({ commit }, payload) {      commit('UPDATE_TODO', payload)    },    \/\/ \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u0437\u0430\u0434\u0430\u0447\u0438    removeTodo({ commit }, id) {      commit('REMOVE_TODO', id)    },    \/\/ \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0435 \u0432\u0441\u0435\u0445 \u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0445 \u0437\u0430\u0434\u0430\u0447    completeTodos({ commit }) {      commit('COMPLETE_TODOS')    },    \/\/ \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u044b\u0445 \u0437\u0430\u0434\u0430\u0447    clearCompleted({ commit }) {      commit('CLEAR_COMPLETED')    },    \/\/ \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0437\u0430\u0434\u0430\u0447 \u0432 \u0411\u0414    saveTodos({ commit, state, dispatch }) {      state.status = 'loading'      postTodos(state.todos)        .then((message) => {          commit('SAVE_TODOS', message)        })        .then(() => {          dispatch('giveMeSomeTime')        })    },    \/\/ \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0444\u0438\u043b\u044c\u0442\u0440\u0430    setFilter({ commit }, filter) {      commit('SET_FILTER', filter)    },    \/\/ \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0438 \u043f\u0435\u0440\u0435\u0434 \u043e\u0447\u0438\u0441\u0442\u043a\u043e\u0439 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f    giveMeSomeTime({ commit }) {      const timerId = setTimeout(() => {        commit('CLEAR_MESSAGE')        clearTimeout(timerId)      }, 1500)    }  },  \/\/ \u0413\u0435\u0442\u0442\u0435\u0440\u044b - \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0447\u0430\u0441\u0442\u0438 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f  getters: {    \/\/ \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u043e\u0442\u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0437\u0430\u0434\u0430\u0447    filteredTodos: ({ todos, filter }) => {      if (filter === 'all') return todos      return filter === 'active'        ? todos.filter((todo) => !todo.done)        : todos.filter((todo) => todo.done)    },    \/\/ \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0438    todoStats: ({ todos }) => {      const total = todos.length      const completed = todos.filter((todo) => todo.done).length      const active = total - completed      const percent = total === 0 ? 0 : Math.round((active \/ total) * 100)       return {        total,        completed,        active,        percent      }    }  } })<\/code><\/pre>\n<p>  <\/p>\n<p>\u0412 \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d\u043d\u043e\u043c \u043a\u043e\u0434\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d \u0442\u0430\u043a\u043e\u0439 \u0436\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b, \u043a\u0430\u043a \u0438 \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0441 <code>Redux<\/code>, \u043d\u043e \u0441\u0430\u043c\u043e\u0433\u043e \u043a\u043e\u0434\u0430 \u0432 2 \u0440\u0430\u0437\u0430 \u043c\u0435\u043d\u044c\u0448\u0435, \u0434\u0430 \u0438 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u043d\u044f\u0442\u043d\u0430\u044f \u0438 \u043f\u0440\u043e\u0441\u0442\u0430\u044f. \u0422\u0430\u043a \u0447\u0442\u043e \u043f\u043e \u0434\u0430\u043d\u043d\u043e\u043c\u0443 \u043a\u0440\u0438\u0442\u0435\u0440\u0438\u044e \u044f \u043f\u0440\u0438\u0441\u0432\u0430\u0438\u0432\u0430\u044e \u043f\u043e\u0431\u0435\u0434\u0443 <code>Vuex<\/code>. \u041d\u043e \u0447\u0442\u043e \u043d\u0430\u0441\u0447\u0435\u0442 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438? \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u0441\u043b\u043e\u0436\u043d\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 <code>Redux<\/code> \u2014 \u0437\u0430\u043b\u043e\u0433 \u0432\u044b\u0441\u043e\u043a\u043e\u0439 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0439 \u0447\u0442\u0435\u043d\u0438\u044f \/ \u0437\u0430\u043f\u0438\u0441\u0438 \u0434\u0430\u043d\u043d\u044b\u0445? \u0421\u043a\u043e\u0440\u043e \u043c\u044b \u044d\u0442\u043e \u0432\u044b\u044f\u0441\u043d\u0438\u043c, \u043d\u043e \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u0440\u043e\u0432\u0435\u0434\u0435\u043c \u043f\u043e\u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043d\u043e\u0435 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0435 \u043d\u0430\u0448\u0438\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439.<\/p>\n<p>  <\/p>\n<h2 id=\"komponenty-prilozheniy\">\u041a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439<\/h2>\n<p>  <\/p>\n<p>\u0414\u0430\u0431\u044b \u043d\u0435 \u0443\u0442\u043e\u043c\u043b\u044f\u0442\u044c \u0442\u0435\u0445 \u0447\u0438\u0442\u0430\u0442\u0435\u043b\u0435\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u0434\u0430\u043d\u043d\u044b\u0439 \u0440\u0430\u0437\u0434\u0435\u043b \u043d\u0435\u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0435\u043d, \u044f \u043f\u043e\u043c\u0435\u0449\u0443 \u043a\u043e\u0434 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 \u043f\u043e\u0434 \u043a\u0430\u0442.<\/p>\n<p>  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u0424\u0438\u043a\u0442\u0438\u0432\u043d\u0430\u044f \u0431\u0430\u0437\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 (db.json)<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"plaintext\">{  \"todos\": [    {      \"id\": \"1\",      \"text\": \"Eat\",      \"done\": true,      \"edit\": false    },    {      \"id\": \"2\",      \"text\": \"Code\",      \"done\": true,      \"edit\": false    },    {      \"id\": \"3\",      \"text\": \"Sleep\",      \"done\": false,      \"edit\": false    },    {      \"id\": \"4\",      \"text\": \"Repeat\",      \"done\": false,      \"edit\": false    }  ] }<\/code><\/pre>\n<\/div><\/div>\n<p>  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0444\u0430\u0439\u043b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<p><em>React (index.jsx)<\/em><\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">import React, { StrictMode } from 'react' import { render } from 'react-dom' \/\/ \u041f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440 \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0432 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b import { Provider } from 'react-redux' \/\/ \u0425\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u0438 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0437\u0430\u0434\u0430\u0447 \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0438 \u043f\u0435\u0440\u0435\u0434 \u043e\u0447\u0438\u0441\u0442\u043a\u043e\u0439 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430 import { store, fetchTodos, giveMeSomeTime } from '.\/store'  \/\/ \u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f import App from '.\/App'  \/\/ \u041e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u0432 \u0440\u0435\u0434\u0443\u043a\u0442\u043e\u0440 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044e \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0437\u0430\u0434\u0430\u0447 \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \/\/ \u0438 \u0441\u043b\u0435\u0434\u043e\u043c \u0437\u0430 \u043d\u0435\u0439 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044e \u0434\u043b\u044f \u043e\u0447\u0438\u0441\u0442\u043a\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0441 \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u043e\u0439 \u0432 2 \u0441\u0435\u043a\u0443\u043d\u0434\u044b store.dispatch(fetchTodos()).then(() => store.dispatch(giveMeSomeTime()))  render(  &lt;StrictMode>    {\/* \u041f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u0440\u043e\u043f\u0430 `store` *\/}    &lt;Provider store={store}>      &lt;App \/>    &lt;\/Provider>  &lt;\/StrictMode>,  document.getElementById('root') )<\/code><\/pre>\n<p>  <\/p>\n<p><em>Vue (main.js)<\/em><\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">import { createApp } from 'vue' \/\/ \u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f import App from '.\/App.vue' \/\/ \u0425\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 import store from '.\/store' \/\/ \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0437\u0430\u0434\u0430\u0447\u0438 \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 store.dispatch('fetchTodos')  createApp(App).use(store).mount('#app')<\/code><\/pre>\n<\/div><\/div>\n<p>  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<p><em>React (App.jsx)<\/em><\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ \u0425\u0443\u043a \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u0435\u043b\u0435\u043a\u0442\u043e\u0440\u043e\u0432 import { useSelector } from 'react-redux' \/\/ \u041a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f import New from '.\/components\/New' import Filters from '.\/components\/Filters' import List from '.\/components\/List' import Controls from '.\/components\/Controls' import Stats from '.\/components\/Stats' import Loader from '.\/components\/Loader' \/\/ \u0421\u0435\u043b\u0435\u043a\u0442\u043e\u0440 \u0434\u043b\u044f \u0432\u044b\u0431\u043e\u0440\u043a\u0438 \u0432\u0441\u0435\u0445 \u0437\u0430\u0434\u0430\u0447 import { selectTotal } from '.\/store'  export default function App() {  const dispatch = useDispatch()  \/\/ \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043e\u0431\u0449\u0435\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0437\u0430\u0434\u0430\u0447  const total = useSelector(selectTotal)  \/\/ \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0438\u043d\u0434\u0438\u043a\u0430\u0442\u043e\u0440 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438  const status = useSelector(({ todos }) => todos.status)  \/\/ \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435  const message = useSelector(({ todos }) => todos.message)   \/**   * \u041b\u043e\u0433\u0438\u043a\u0430 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433\u0430:   * - \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0434\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u043e\u0432\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438 (New) \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u0442\u0441\u044f \u0432\u0441\u0435\u0433\u0434\u0430   * - \u0435\u0441\u043b\u0438 \u0435\u0441\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435, \u043e\u043d\u043e \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u0442\u0441\u044f   * - \u0435\u0441\u043b\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 (status === 'loading'), \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0438\u043d\u0434\u0438\u043a\u0430\u0442\u043e\u0440   * - \u0435\u0441\u043b\u0438 \u0432 \u043c\u0430\u0441\u0441\u0438\u0432\u0435 \u0435\u0441\u0442\u044c \u0445\u043e\u0442\u044f \u0431\u044b \u043e\u0434\u043d\u0430 \u0437\u0430\u0434\u0430\u0447\u0430 (total > 0),   * \u0440\u0435\u043d\u0434\u0435\u0440\u044f\u0442\u0441\u044f \u0432\u0441\u0435 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b, \u0432 \u043f\u0440\u043e\u0442\u0438\u0432\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435,   * \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u043d\u043e\u043f\u043a\u0430 \u0434\u043b\u044f \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0437\u0430\u0434\u0430\u0447 \u0438\u0437 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 `Controls`   *\/  return (    &lt;div      className='container d-flex flex-column text-center mt-2 mb-2'      style={{ maxWidth: '600px' }}    >      &lt;h1 className='mb-4'>Modern Redux Todo App&lt;\/h1>      &lt;New \/>      {message.text ? (        &lt;div          className={`alert ${            message.type === 'success' ? 'alert-success' : 'alert-danger'          } position-fixed top-50 start-50 translate-middle`}          role='alert'          style={{ zIndex: 1 }}        >          {message.text}        &lt;\/div>      ) : null}      {status === 'loading' ? (        &lt;Loader \/>      ) : total ? (        &lt;>          &lt;Stats \/>          &lt;div className='row'>            &lt;Filters \/>            &lt;List \/>            &lt;Controls \/>          &lt;\/div>        &lt;\/>      ) : (        &lt;div className='d-flex justify-content-end'>          &lt;Controls \/>        &lt;\/div>      )}    &lt;\/div>  ) }<\/code><\/pre>\n<p>  <\/p>\n<p><em>Vue (App.vue)<\/em><\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">&lt;template>  &lt;div class=\"container d-flex flex-column text-center mt-2 mb-2\">    &lt;h1 class=\"mb-4\">Modern Vuex Todo App&lt;\/h1>    &lt;New \/>    &lt;div      v-if=\"message.text\"      class=\"alert position-fixed top-50 start-50 translate-middle\"      :class=\"messageClass\"      role=\"alert\"    >      {{ message.text }}    &lt;\/div>    &lt;Loader v-if=\"status === 'loading'\" \/>    &lt;template v-else-if=\"length\">      &lt;Stats \/>      &lt;div class=\"row\">        &lt;Filters \/>        &lt;List \/>        &lt;Controls \/>      &lt;\/div>    &lt;\/template>    &lt;div class=\"d-flex justify-content-end\" v-else>      &lt;Controls \/>    &lt;\/div>  &lt;\/div> &lt;\/template>  &lt;script> \/\/ \u041a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f import New from '.\/components\/New' import Stats from '.\/components\/Stats' import Filters from '.\/components\/Filters' import List from '.\/components\/List' import Controls from '.\/components\/Controls' import Loader from '.\/components\/Loader'  export default {  name: 'App',  components: { New, Stats, Filters, List, Controls, Loader },  computed: {    \/\/ \u0412\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435    message() {      return this.$store.state.message    },    \/\/ \u0412\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u043c CSS-\u043a\u043b\u0430\u0441\u0441 \u0434\u043b\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f    messageClass() {      return this.message.type === 'success' ? 'alert-success' : 'alert-danger'    },    \/\/ \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0441\u0442\u0430\u0442\u0443\u0441 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f    status() {      return this.$store.state.status    },    \/\/ \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0434\u043b\u0438\u043d\u0443 \u043c\u0430\u0441\u0441\u0438\u0432\u0430 \u0441 \u0437\u0430\u0434\u0430\u0447\u0430\u043c\u0438    length() {      return this.$store.state.todos.length    }  } } &lt;\/script>  &lt;style> .container {   max-width: 600px; } .alert {   z-index: 1; } &lt;\/style><\/code><\/pre>\n<\/div><\/div>\n<p>  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u041a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0441\u043f\u0438\u0441\u043a\u0430<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<p><strong>\u0421\u043f\u0438\u0441\u043e\u043a<\/strong><\/p>\n<p>  <\/p>\n<p><em>React (index.jsx)<\/em><\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ \u0425\u0443\u043a \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u0435\u043b\u0435\u043a\u0442\u043e\u0440\u043e\u0432 import { useSelector } from 'react-redux' \/\/ \u0421\u0435\u043b\u0435\u043a\u0442\u043e\u0440 \u0434\u043b\u044f \u0432\u044b\u0431\u043e\u0440\u043a\u0438 \u043e\u0442\u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0437\u0430\u0434\u0430\u0447 import { selectFilteredTodos } from '..\/..\/store' \/\/ \u041e\u0431\u044b\u0447\u043d\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0441\u043f\u0438\u0441\u043a\u0430 import Regular from '.\/Regular' \/\/ \u042d\u043b\u0435\u043c\u0435\u043d\u0442 \u0441\u043f\u0438\u0441\u043a\u0430 \u0434\u043b\u044f \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0437\u0430\u0434\u0430\u0447\u0438 import Edit from '.\/Edit'  export default function List() {  \/\/ \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043e\u0442\u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0437\u0430\u0434\u0430\u0447\u0438  const filteredTodos = useSelector(selectFilteredTodos)   \/**   * \u041b\u043e\u0433\u0438\u043a\u0430 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433\u0430:   * - \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0442\u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0437\u0430\u0434\u0430\u0447\u0438   * - \u0438 \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0438\u043d\u0434\u0438\u043a\u0430\u0442\u043e\u0440\u0430 \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0437\u0430\u0434\u0430\u0447\u0438,   * \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043c \u0442\u043e\u0442 \u0438\u043b\u0438 \u0438\u043d\u043e\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0441\u043f\u0438\u0441\u043a\u0430   *\/  return (    &lt;div className=' col-6'>      &lt;h3>Todos&lt;\/h3>      &lt;ul className='list-group'>        {filteredTodos.map((todo) =>          todo.edit ? (            &lt;Edit key={todo.id} todo={todo} \/>          ) : (            &lt;Regular key={todo.id} todo={todo} \/>          )        )}      &lt;\/ul>    &lt;\/div>  ) }<\/code><\/pre>\n<p>  <\/p>\n<p><em>Vue (index.vue)<\/em><\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">&lt;template>  &lt;div class=\"col-6\">    &lt;h3>Todos&lt;\/h3>    &lt;ul v-show=\"todos.length\">      &lt;li        v-for=\"todo in todos\"        :key=\"todo.id\"        class=\"list-group-item d-flex align-items-center\"      >        &lt;Regular :todo=\"todo\" v-if=\"!todo.edit\" \/>        &lt;Edit :todo=\"todo\" v-else \/>      &lt;\/li>    &lt;\/ul>  &lt;\/div> &lt;\/template>  &lt;script> \/\/ \u0423\u0442\u0438\u043b\u0438\u0442\u0430 \u0434\u043b\u044f \u043f\u0440\u0438\u0432\u044f\u0437\u043a\u0438 \u0433\u0435\u0442\u0442\u0435\u0440\u043e\u0432 \u043a \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0443 import { mapGetters } from 'vuex' \/\/ \u041a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0434\u043b\u044f \u043e\u0431\u044b\u0447\u043d\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438 import Regular from '.\/Regular' \/\/ \u041a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0434\u043b\u044f \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u0443\u0435\u043c\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438 import Edit from '.\/Edit'  export default {  name: 'List',  components: { Regular, Edit },  computed: {    \/\/ \u041f\u0440\u0438\u0432\u044f\u0437\u044b\u0432\u0430\u0435\u043c \u0433\u0435\u0442\u0442\u0435\u0440 \u043a \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0443    ...mapGetters({ todos: 'filteredTodos' })  } } &lt;\/script><\/code><\/pre>\n<p>  <\/p>\n<p><strong>\u041a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0434\u043b\u044f \u043e\u0431\u044b\u0447\u043d\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438<\/strong><\/p>\n<p>  <\/p>\n<p><em>React (Regular.jsx)<\/em><\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ \u0425\u0443\u043a \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u0438\u0441\u043f\u0435\u0442\u0447\u0435\u0440\u0430 import { useDispatch } from 'react-redux' \/\/ \u041e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u0434\u043b\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u0437\u0430\u0434\u0430\u0447\u0438 import { updateTodo, removeTodo } from '..\/..\/store'  export default function Regular({ todo }) {  \/\/ \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0434\u0438\u0441\u043f\u0435\u0442\u0447\u0435\u0440  const dispatch = useDispatch()  \/\/ \u0418\u0437\u0432\u043b\u0435\u043a\u0430\u0435\u043c \u0432\u0441\u0435 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u0437\u0430\u0434\u0430\u0447\u0438  const { id, text, done, edit } = todo   return (    &lt;li className='list-group-item d-flex align-items-center'>      &lt;input        type='checkbox'        checked={done}        onChange={() => dispatch(updateTodo({ id, changes: { done: !done } }))}        className='form-check-input'      \/>      &lt;p        className={`flex-grow-1 m-0 ${          done ? 'text-muted text-decoration-line-through' : ''        }`}      >        {text}      &lt;\/p>      &lt;button        onClick={() => dispatch(updateTodo({ id, changes: { edit: !edit } }))}        className='btn btn-outline-info'        disabled={done}      >        &lt;i className='bi bi-pencil'>&lt;\/i>      &lt;\/button>      &lt;button        onClick={() => dispatch(removeTodo(id))}        className='btn btn-outline-danger'      >        &lt;i className='bi bi-trash'>&lt;\/i>      &lt;\/button>    &lt;\/li>  ) }<\/code><\/pre>\n<p>  <\/p>\n<p><em>Vue (Regular.vue)<\/em><\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">&lt;template>  &lt;input    type=\"checkbox\"    :checked=\"todo.done\"    @change=\"completeTodo\"    class=\"form-check-input\"  \/>  &lt;p class=\"flex-grow-1 m-0\" :class=\"todoClass\">    {{ todo.text }}  &lt;\/p>  &lt;button @click=\"editTodo\" class=\"btn btn-outline-info\" :disabled=\"todo.done\">    &lt;i class=\"bi bi-pencil\">&lt;\/i>  &lt;\/button>  &lt;button @click=\"removeTodo(todo)\" class=\"btn btn-outline-danger\">    &lt;i class=\"bi bi-trash\">&lt;\/i>  &lt;\/button> &lt;\/template>  &lt;script> \/\/ \u0423\u0442\u0438\u043b\u0438\u0442\u0430 \u0434\u043b\u044f \u043f\u0440\u0438\u0432\u044f\u0437\u043a\u0438 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0439 \u043a \u043c\u0435\u0442\u043e\u0434\u0430\u043c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 import { mapActions } from 'vuex'  export default {  name: 'Regular',  props: ['todo'],  computed: {    \/\/ \u0412\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u043c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 CSS-\u043a\u043b\u0430\u0441\u0441 \u0434\u043b\u044f \u0437\u0430\u0434\u0430\u0447\u0438    todoClass() {      return this.todo.done ? 'text-muted text-decoration-line-through' : ''    }  },  methods: {    \/\/ \u041f\u0440\u0438\u0432\u044f\u0437\u044b\u0432\u0430\u0435\u043c \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u043a \u043c\u0435\u0442\u043e\u0434\u0430\u043c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430    ...mapActions(['updateTodo', 'removeTodo']),    \/\/ \u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0438\u043d\u0434\u0438\u043a\u0430\u0442\u043e\u0440\u0430 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u0437\u0430\u0434\u0430\u0447\u0438    completeTodo() {      this.updateTodo({ id: this.todo.id, changes: { done: !this.todo.done } })    },    \/\/ \u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0438\u043d\u0434\u0438\u043a\u0430\u0442\u043e\u0440\u0430 \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0437\u0430\u0434\u0430\u0447\u0438    editTodo() {      this.updateTodo({ id: this.todo.id, changes: { edit: !this.todo.edit } })    }  } } &lt;\/script><\/code><\/pre>\n<p>  <\/p>\n<p><strong>\u041a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0434\u043b\u044f \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u0443\u0435\u043c\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438<\/strong><\/p>\n<p>  <\/p>\n<p><em>React (Edit.jsx)<\/em><\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">import { useState, useEffect } from 'react' \/\/ \u0425\u0443\u043a \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u0438\u0441\u043f\u0435\u0442\u0447\u0435\u0440\u0430 import { useDispatch } from 'react-redux' \/\/ \u041e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u0434\u043b\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u0437\u0430\u0434\u0430\u0447\u0438 import { updateTodo, removeTodo } from '..\/..\/store'  export default function Edit({ todo }) {  \/\/ \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0434\u0438\u0441\u043f\u0435\u0442\u0447\u0435\u0440  const dispatch = useDispatch()  \/\/ \u0418\u0437\u0432\u043b\u0435\u043a\u0430\u0435\u043c \u0432\u0441\u0435 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u0437\u0430\u0434\u0430\u0447\u0438, \u043a\u0440\u043e\u043c\u0435 \u0438\u043d\u0434\u0438\u043a\u0430\u0442\u043e\u0440\u0430 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u043e\u0441\u0442\u0438  const { id, text, edit } = todo  \/\/ \u041b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0434\u043b\u044f \u0442\u0435\u043a\u0441\u0442\u0430 \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u0443\u0435\u043c\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438  const [newText, setNewText] = useState(text)   \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0442\u0435\u043a\u0441\u0442\u0430  const onChangeText = ({ target: { value } }) => {    const trimmed = value.replace(\/\\s{2,}\/g, ' ').trim()    setNewText(trimmed)  }  \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f  const onFinishEdit = () => {    \/\/ \u0415\u0441\u043b\u0438 \u0442\u0435\u043a\u0441\u0442 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442, \u0432\u0435\u0440\u043e\u044f\u0442\u043d\u043e, \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0445\u043e\u0447\u0435\u0442 \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u0437\u0430\u0434\u0430\u0447\u0443    if (!newText) {      return dispatch(removeTodo(id))    }    \/\/ \u041e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044e \u0434\u043b\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0442\u0435\u043a\u0441\u0442\u0430 \u0437\u0430\u0434\u0430\u0447\u0438    dispatch(updateTodo({ id, changes: { text: newText, edit: !edit } }))  }  \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u043e\u0442\u043c\u0435\u043d\u044b \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f  const onCancelEdit = () => {    \/\/ \u041e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044e \u0434\u043b\u044f \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0438\u043d\u0434\u0438\u043a\u0430\u0442\u043e\u0440\u0430 \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f    dispatch(updateTodo({ id, changes: { edit: !edit } }))  }   \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043d\u0430\u0436\u0430\u0442\u0438\u044f \u043a\u043b\u0430\u0432\u0438\u0448 \u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u044b:  \/\/ \u0435\u0441\u043b\u0438 \u043d\u0430\u0436\u0430\u0442\u0430 \u043a\u043b\u0430\u0432\u0438\u0448\u0430 \"Enter\", \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u0435\u043c \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435,  \/\/ \u0435\u0441\u043b\u0438 \u043d\u0430\u0436\u0430\u0442\u0430 \u043a\u043b\u0430\u0432\u0438\u0448\u0430 \"Escape\", \u043e\u0442\u043c\u0435\u043d\u044f\u0435\u043c \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435  const onKeyDown = ({ key }) => {    switch (key) {      case 'Enter':        onFinishEdit()        break      case 'Escape':        onCancelEdit()        break      default:        break    }  }   \/\/ \u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u043c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043d\u0430\u0436\u0430\u0442\u0438\u044f \u043a\u043b\u0430\u0432\u0438\u0448  \/\/ \u0438 \u0443\u0434\u0430\u043b\u044f\u0435\u043c \u0435\u0433\u043e \u043f\u0440\u0438 \u0440\u0430\u0437\u043c\u043e\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430  useEffect(() => {    window.addEventListener('keydown', onKeyDown)    return () => {      window.removeEventListener('keydown', onKeyDown)    }  })   return (    &lt;li className='list-group-item d-flex align-items-center'>      &lt;input        type='text'        value={newText}        onChange={onChangeText}        className='form-control flex-grow-1'      \/>      &lt;button onClick={onFinishEdit} className='btn btn-outline-success'>        &lt;i className='bi bi-check'>&lt;\/i>      &lt;\/button>      &lt;button onClick={onCancelEdit} className='btn btn-outline-warning'>        &lt;i className='bi bi-x-square'>&lt;\/i>      &lt;\/button>    &lt;\/li>  ) }<\/code><\/pre>\n<p>  <\/p>\n<p><em>Vue (Edit.vue)<\/em><\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">&lt;template>  &lt;input type=\"text\" v-model=\"newText\" class=\"form-control flex-grow-1\" \/>  &lt;button @click=\"finishEdit\" class=\"btn btn-outline-success\">    &lt;i class=\"bi bi-check\">&lt;\/i>  &lt;\/button>  &lt;button @click=\"cancelEdit\" class=\"btn btn-outline-warning\">    &lt;i class=\"bi bi-x-square\">&lt;\/i>  &lt;\/button> &lt;\/template>  &lt;script> \/\/ \u0423\u0442\u0438\u043b\u0438\u0442\u0430 \u0434\u043b\u044f \u043f\u0440\u0438\u0432\u044f\u0437\u043a\u0438 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0439 \u043a \u043c\u0435\u0442\u043e\u0434\u0430\u043c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 import { mapActions } from 'vuex'  export default {  name: 'Edit',  props: ['todo'],  data() {    \/\/ \u041b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0434\u043b\u044f \u0442\u0435\u043a\u0441\u0442\u0430 \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u0443\u0435\u043c\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438    return {      newText: this.todo.text    }  },  \/\/ \u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u043c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043d\u0430\u0436\u0430\u0442\u0438\u044f \u043a\u043b\u0430\u0432\u0438\u0448 \u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u044b \u043f\u0440\u0438 \u043c\u043e\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430  created() {    window.addEventListener('keydown', this.onKeyDown)  },  \/\/ \u0423\u0434\u0430\u043b\u044f\u0435\u043c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043d\u0430\u0436\u0430\u0442\u0438\u044f \u043a\u043b\u0430\u0432\u0438\u0448 \u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u044b \u043f\u0440\u0438 \u0440\u0430\u0437\u043c\u043e\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430  unmounted() {    window.removeEventListener('keydown', this.onKeyDown)  },  methods: {    \/\/ \u041f\u0440\u0438\u0432\u044f\u0437\u044b\u0432\u0430\u0435\u043c \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u043a \u043c\u0435\u0442\u043e\u0434\u0430\u043c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430    ...mapActions(['updateTodo', 'removeTodo']),    \/\/ \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043d\u0430\u0436\u0430\u0442\u0438\u044f \u043a\u043b\u0430\u0432\u0438\u0448 \u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u044b    onKeyDown({ key }) {      switch (key) {        \/\/ \u0415\u0441\u043b\u0438 \u043d\u0430\u0436\u0430\u0442\u0430 \u043a\u043b\u0430\u0432\u0438\u0448\u0430 `Enter`, \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c \u043c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f        case 'Enter':          this.finishEdit()          break        \/\/ \u0415\u0441\u043b\u0438 \u043d\u0430\u0436\u0430\u0442\u0430 \u043a\u043b\u0430\u0432\u0438\u0448\u0430 `Escape`, \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c \u043c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043e\u0442\u043c\u0435\u043d\u044b \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f        case 'Escape':          this.cancelEdit()          break        default:          break      }    },    \/\/ \u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f    finishEdit() {      const text = this.newText.replace(\/\\s{2,}\/g, ' ').trim()      if (!text) return this.removeTodo(this.todo)      this.updateTodo({        id: this.todo.id,        changes: { text, edit: !this.todo.edit }      })    },    \/\/ \u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043e\u0442\u043c\u0435\u043d\u044b \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f    cancelEdit() {      this.updateTodo({ id: this.todo.id, changes: { edit: !this.todo.edit } })    }  } } &lt;\/script><\/code><\/pre>\n<\/div><\/div>\n<p>  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u041a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0434\u043b\u044f \u043a\u043d\u043e\u043f\u043e\u043a \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<p><em>React (Controls.jsx)<\/em><\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ \u0425\u0443\u043a\u0438 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u0438\u0441\u043f\u0435\u0442\u0447\u0435\u0440\u0430 \u0438 \u0441\u0435\u043b\u0435\u043a\u0442\u043e\u0440\u043e\u0432 import { useDispatch, useSelector } from 'react-redux' \/\/ \u041e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u0434\u043b\u044f \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u0432\u0441\u0435\u0445 \u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0445 \u0437\u0430\u0434\u0430\u0447, \/\/ \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u044b\u0445 \u0437\u0430\u0434\u0430\u0447, \/\/ \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0437\u0430\u0434\u0430\u0447 \u0432 \u0411\u0414, \/\/ \u043e\u0447\u0438\u0441\u0442\u043a\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \/\/ \u0438 \u0441\u0435\u043b\u0435\u043a\u0442\u043e\u0440 \u0434\u043b\u044f \u0432\u044b\u0431\u043e\u0440\u043a\u0438 \u0432\u0441\u0435\u0445 \u0437\u0430\u0434\u0430\u0447 import {  completeAllTodos,  clearCompletedTodos,  saveTodos,  giveMeSomeTime,  selectAll } from '..\/store'  export default function Controls() {  \/\/ \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0434\u0438\u0441\u043f\u0435\u0442\u0447\u0435\u0440  const dispatch = useDispatch()  \/\/ \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0432\u0441\u0435 \u0437\u0430\u0434\u0430\u0447\u0438  const todos = useSelector(selectAll)   \/**   * \u041b\u043e\u0433\u0438\u043a\u0430 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433\u0430:   * - \u0435\u0441\u043b\u0438 \u0432 \u043c\u0430\u0441\u0441\u0438\u0432\u0435 \u0435\u0441\u0442\u044c \u0445\u043e\u0442\u044f \u0431\u044b \u043e\u0434\u043d\u0430 \u0437\u0430\u0434\u0430\u0447\u0430,   * \u0440\u0435\u043d\u0434\u0435\u0440\u044f\u0442\u0441\u044f \u043a\u043d\u043e\u043f\u043a\u0438 \u0434\u043b\u044f \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u0432\u0441\u0435\u0445 \u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0445 \u0437\u0430\u0434\u0430\u0447, \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u044b\u0445 \u0437\u0430\u0434\u0430\u0447 \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0437\u0430\u0434\u0430\u0447 \u0432 \u0411\u0414,   * \u0432 \u043f\u0440\u043e\u0442\u0438\u0432\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u043d\u043e\u043f\u043a\u0430 \u0434\u043b\u044f \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0437\u0430\u0434\u0430\u0447   *\/  return (    &lt;div className='col-3 d-flex flex-column'>      &lt;h3>Controls&lt;\/h3>      {todos.length ? (        &lt;>          &lt;button            onClick={() => dispatch(completeAllTodos())}            className='btn btn-info mb-2'          >            Complete          &lt;\/button>          &lt;button            onClick={() => dispatch(clearCompletedTodos())}            className='btn btn-danger mb-2'          >            Clear          &lt;\/button>        &lt;\/>      ) : null}      &lt;button        onClick={() =>          \/\/ \u041e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044e \u0434\u043b\u044f \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0437\u0430\u0434\u0430\u0447          \/\/ \u0438 \u0441\u043b\u0435\u0434\u043e\u043c \u0437\u0430 \u043d\u0435\u0439 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044e \u0434\u043b\u044f \u043e\u0447\u0438\u0441\u0442\u043a\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0441 \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u043e\u0439 \u0432 2 \u0441\u0435\u043a\u0443\u043d\u0434\u044b          dispatch(saveTodos(todos)).then(() => dispatch(giveMeSomeTime()))        }        className='btn btn-success'      >        Save      &lt;\/button>    &lt;\/div>  ) }<\/code><\/pre>\n<p>  <\/p>\n<p><em>Vue (Controls.vue)<\/em><\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">&lt;template>  &lt;div class=\"col-3 d-flex flex-column\">    &lt;h3>Controls&lt;\/h3>    &lt;template v-if=\"length\">      &lt;button @click=\"completeTodos\" class=\"btn btn-info mb-2\">Complete&lt;\/button>      &lt;button @click=\"clearCompleted\" class=\"btn btn-danger mb-2\">Clear&lt;\/button>    &lt;\/template>    &lt;button @click=\"saveTodos\" class=\"btn btn-success\">Save&lt;\/button>  &lt;\/div> &lt;\/template>  &lt;script> \/\/ \u0423\u0442\u0438\u043b\u0438\u0442\u0430 \u0434\u043b\u044f \u043f\u0440\u0438\u0432\u044f\u0437\u043a\u0438 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0439 \u043a \u043c\u0435\u0442\u043e\u0434\u0430\u043c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 import { mapActions } from 'vuex'  export default {  name: 'Controls',  computed: {    \/\/ \u0412\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u043c \u0434\u043b\u0438\u043d\u0443 \u043c\u0430\u0441\u0441\u0438\u0432\u0430 \u0441 \u0437\u0430\u0434\u0430\u0447\u0430\u043c\u0438    length() {      return this.$store.state.todos.length    }  },  methods: {    \/\/ \u041f\u0440\u0438\u0432\u044f\u0437\u044b\u0432\u0430\u0435\u043c \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u043a \u043c\u0435\u0442\u043e\u0434\u0430\u043c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430    ...mapActions(['completeTodos', 'clearCompleted', 'saveTodos'])  } } &lt;\/script><\/code><\/pre>\n<\/div><\/div>\n<p>  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u041a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0434\u043b\u044f \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<p><em>React (Filters.jsx)<\/em><\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ \u0425\u0443\u043a\u0438 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u0438\u0441\u043f\u0435\u0442\u0447\u0435\u0440\u0430 \u0438 \u0441\u0435\u043b\u0435\u043a\u0442\u043e\u0440\u043e\u0432 import { useDispatch, useSelector } from 'react-redux' \/\/ \u041e\u043f\u0435\u0440\u0430\u0446\u0438\u044f \u0434\u043b\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0444\u0438\u043b\u044c\u0442\u0440\u0430 import { setFilter } from '..\/store'  export default function Filters() {  \/\/ \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0434\u0438\u0441\u043f\u0435\u0442\u0447\u0435\u0440  const dispatch = useDispatch()  \/\/ \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0442\u0435\u043a\u0443\u0449\u0435\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0444\u0438\u043b\u044c\u0442\u0440\u0430  const { status } = useSelector((state) => state.filter)   return (    &lt;div className='col-3'>      &lt;h3>Filters&lt;\/h3>      {['all', 'active', 'completed'].map((filter) => (        &lt;div key={filter} className='form-check' style={{ textAlign: 'left' }}>          &lt;input            id={filter}            type='radio'            checked={filter === status}            onChange={() => dispatch(setFilter(filter))}            className='form-check-input'          \/>          &lt;label htmlFor={filter} className='form-check-label'>            {filter.toUpperCase()}          &lt;\/label>        &lt;\/div>      ))}    &lt;\/div>  ) }<\/code><\/pre>\n<p>  <\/p>\n<p><em>Vue (Filters.vue)<\/em><\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">&lt;template>  &lt;div class=\"col-3\">    &lt;h3>Filters&lt;\/h3>    &lt;div      v-for=\"filter in ['all', 'active', 'completed']\"      :key=\"filter\"      class=\"form-check text-left\"    >      &lt;input        :id=\"filter\"        type=\"radio\"        :checked=\"filter === currentFilter\"        @click=\"setFilter(filter)\"        class=\"form-check-input\"      \/>      &lt;label :for=\"filter\" class=\"form-check-label\">        {{ filter.toUpperCase() }}      &lt;\/label>    &lt;\/div>  &lt;\/div> &lt;\/template>  &lt;script> \/\/ \u0423\u0442\u0438\u043b\u0438\u0442\u0430 \u0434\u043b\u044f \u043f\u0440\u0438\u0432\u044f\u0437\u043a\u0438 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0439 \u043a \u043c\u0435\u0442\u043e\u0434\u0430\u043c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 import { mapActions } from 'vuex'  export default {  name: 'Filters',  computed: {    \/\/ \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0442\u0435\u043a\u0443\u0449\u0435\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0444\u0438\u043b\u044c\u0442\u0440\u0430    currentFilter() {      return this.$store.state.filter    }  },  methods: {    \/\/ \u041f\u0440\u0438\u0432\u044f\u0437\u044b\u0432\u0430\u0435\u043c \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044e \u043a \u043c\u0435\u0442\u043e\u0434\u0443 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430    ...mapActions(['setFilter'])  } } &lt;\/script>  &lt;style scoped> .text-left {   text-align: left !important; } &lt;\/style><\/code><\/pre>\n<\/div><\/div>\n<p>  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u0418\u043d\u0434\u0438\u043a\u0430\u0442\u043e\u0440 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<p><em>React (Loader.jsx)<\/em><\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ \u0418\u043d\u0434\u0438\u043a\u0430\u0442\u043e\u0440 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 export default function Loader() {  return (    &lt;div className='spinner-border text-primary m-auto' role='status'>      &lt;span className='visually-hidden'>Loading...&lt;\/span>    &lt;\/div>  ) }<\/code><\/pre>\n<p>  <\/p>\n<p><em>Vue (Loader.vue)<\/em><\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">&lt;template>  &lt;div class=\"spinner-border text-primary m-auto\" role=\"status\">    &lt;span class=\"visually-hidden\">Loading...&lt;\/span>  &lt;\/div> &lt;\/template>  &lt;script> export default {   name: 'Loader' } &lt;\/script><\/code><\/pre>\n<\/div><\/div>\n<p>  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u041a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0434\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u043e\u0432\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<p><em>React (New.jsx)<\/em><\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">import { useState } from 'react' \/\/ \u0425\u0443\u043a \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u0438\u0441\u043f\u0435\u0442\u0447\u0435\u0440\u0430 import { useDispatch } from 'react-redux' \/\/ \u0423\u0442\u0438\u043b\u0438\u0442\u0430 \u0434\u043b\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0445 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u043e\u0432 import { nanoid } from '@reduxjs\/toolkit' \/\/ \u041e\u043f\u0435\u0440\u0430\u0446\u0438\u044f \u0434\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u043e\u0432\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438 import { addTodo } from '..\/store'  export default function New() {  \/\/ \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0434\u0438\u0441\u043f\u0435\u0442\u0447\u0435\u0440  const dispatch = useDispatch()  \/\/ \u041b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0434\u043b\u044f \u0442\u0435\u043a\u0441\u0442\u0430 \u043d\u043e\u0432\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438  const [text, setText] = useState('')   \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0442\u0435\u043a\u0441\u0442\u0430 \u0437\u0430\u0434\u0430\u0447\u0438  const changeText = ({ target: { value } }) => {    \/\/ \u0417\u0430\u043c\u0435\u043d\u044f\u0435\u043c \u0434\u0432\u0430 \u0438 \u0431\u043e\u043b\u0435\u0435 \u043f\u0440\u043e\u0431\u0435\u043b\u0430 \u043d\u0430 \u043e\u0434\u0438\u043d \u0438 \u0443\u0434\u0430\u043b\u044f\u0435\u043c \u043f\u0440\u043e\u0431\u0435\u043b\u044b \u0432 \u043d\u0430\u0447\u0430\u043b\u0435 \u0438 \u043a\u043e\u043d\u0446\u0435 \u0441\u0442\u0440\u043e\u043a\u0438    const trimmed = value.replace(\/\\s{2,}\/g, ' ').trim()    setText(trimmed)  }   \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0437\u0430\u0434\u0430\u0447\u0438  const onAddTodo = (e) => {    e.preventDefault()     if (!text) return     const newTodo = {      id: nanoid(5),      text,      done: false,      edit: false    }    \/\/ \u041e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044e \u0434\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u043e\u0432\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438    dispatch(addTodo(newTodo))     setText('')  }   return (    &lt;form onSubmit={onAddTodo} className='d-flex mb-4'>      &lt;input        type='text'        placeholder='What needs to be done?'        value={text}        onChange={changeText}        className='form-control flex-grow-1'      \/>      &lt;button className='btn btn-outline-success'>        &lt;i className='bi bi-plus-square'>&lt;\/i>      &lt;\/button>    &lt;\/form>  ) }<\/code><\/pre>\n<p>  <\/p>\n<p><em>Vue (New.vue)<\/em><\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">&lt;template>  &lt;form @submit.prevent=\"addTodoMethod\" class=\"d-flex mb-4\">    &lt;input      type=\"text\"      placeholder=\"What needs to be done?\"      class=\"form-control flex-grow-1\"      v-model=\"text\"    \/>    &lt;button class=\"btn btn-outline-success\">      &lt;i class=\"bi bi-plus-square\">&lt;\/i>    &lt;\/button>  &lt;\/form> &lt;\/template>  &lt;script> \/\/ \u0423\u0442\u0438\u043b\u0438\u0442\u0430 \u0434\u043b\u044f \u043f\u0440\u0438\u0432\u044f\u0437\u043a\u0438 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0439 \u043a \u043c\u0435\u0442\u043e\u0434\u0430\u043c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 import { mapActions } from 'vuex' \/\/ \u0423\u0442\u0438\u043b\u0438\u0442\u0430 \u0434\u043b\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0445 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u043e\u0432 import { nanoid } from 'nanoid'  export default {  name: 'New',  data() {    \/\/ \u041b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0434\u043b\u044f \u0442\u0435\u043a\u0441\u0442\u0430 \u043d\u043e\u0432\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438    return {      text: ''    }  },  methods: {    \/\/ \u041f\u0440\u0438\u0432\u044f\u0437\u044b\u0432\u0430\u0435\u043c \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044e \u043a \u043c\u0435\u0442\u043e\u0434\u0443 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430    ...mapActions(['addTodo']),    \/\/ \u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u043e\u0432\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438    addTodoMethod() {      const trimmed = this.text.replace(\/\\s{2,}\/g, ' ').trim()      if (!trimmed) return      const todo = {        id: nanoid(5),        text: trimmed,        done: false,        edit: false      }      this.addTodo(todo)      this.text = ''    }  } } &lt;\/script><\/code><\/pre>\n<\/div><\/div>\n<p>  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">Last, but not least &#8212; \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0434\u043b\u044f \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0438<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<p><em>React (Stats.jsx)<\/em><\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ \u0425\u0443\u043a \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u0435\u043b\u0435\u043a\u0442\u043e\u0440\u043e\u0432 import { useSelector } from 'react-redux' \/\/ \u0421\u0435\u043b\u0435\u043a\u0442\u043e\u0440 \u0434\u043b\u044f \u0432\u044b\u0431\u043e\u0440\u043a\u0438 \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0438 import { selectTodoStats } from '..\/store'  export default function Stats() {  \/\/ \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0443 (\u043e\u0431\u044a\u0435\u043a\u0442)  const stats = useSelector(selectTodoStats)   \/**   * \u041b\u043e\u0433\u0438\u043a\u0430 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433\u0430:   * - \u043f\u0435\u0440\u0435\u0431\u0438\u0440\u0430\u0435\u043c \u043a\u043b\u044e\u0447\u0438 \u0438 \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u0441 \u0438\u0445 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043e\u043b\u043e\u043d\u043a\u0438-\u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 (\u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c \"\u043a\u0430\u043f\u0438\u0442\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e\" \u043a\u043b\u044e\u0447\u0435\u0439)   * - \u043f\u0435\u0440\u0435\u0431\u0438\u0440\u0430\u0435\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0438 \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u0441 \u0438\u0445 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043e\u0431\u044b\u0447\u043d\u044b\u0435 \u043a\u043e\u043b\u043e\u043d\u043a\u0438   *\/  return (    &lt;div className='row'>      &lt;h3>Statistics&lt;\/h3>      &lt;table className='table text-center'>        &lt;thead>          &lt;tr>            {Object.keys(stats).map(([first, ...rest], index) => (              &lt;th scope='col' key={index}>                {`${first.toUpperCase()}${rest.join('').toLowerCase()}`}              &lt;\/th>            ))}          &lt;\/tr>          &lt;tr>            {Object.values(stats).map((value, index) => (              &lt;td key={index}>{value}&lt;\/td>            ))}          &lt;\/tr>        &lt;\/thead>      &lt;\/table>    &lt;\/div>  ) }<\/code><\/pre>\n<p>  <\/p>\n<p><em>Vue (Stats.vue)<\/em><\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">&lt;template>  &lt;div class=\"row\">    &lt;h3>Statistics&lt;\/h3>    &lt;table class=\"table text-center\">      &lt;thead>        &lt;tr>          &lt;th scope=\"col\" v-for=\"(_, name, index) in todoStats\" :key=\"index\">            {{ `${name[0].toUpperCase()}${name.slice(1).toLowerCase()}` }}          &lt;\/th>        &lt;\/tr>        &lt;tr>          &lt;td v-for=\"(val, _, index) in todoStats\" :key=\"index\">{{ val }}&lt;\/td>        &lt;\/tr>      &lt;\/thead>    &lt;\/table>  &lt;\/div> &lt;\/template>  &lt;script> \/\/ \u0423\u0442\u0438\u043b\u0438\u0442\u0430 \u0434\u043b\u044f \u043f\u0440\u0438\u0432\u044f\u0437\u043a\u0438 \u0433\u0435\u0442\u0442\u0435\u0440\u043e\u0432 \u043a \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0443 import { mapGetters } from 'vuex'  export default {  name: 'Stats',  computed: {    \/\/ \u041f\u0440\u0438\u0432\u044f\u0437\u044b\u0432\u0430\u0435\u043c \u0433\u0435\u0442\u0442\u0435\u0440 \u043a \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0443    ...mapGetters(['todoStats'])  } } &lt;\/script><\/code><\/pre>\n<\/div><\/div>\n<p>  <\/p>\n<p>\u0421\u0432\u043e\u0438\u043c\u0438 \u0432\u043f\u0435\u0447\u0430\u0442\u043b\u0435\u043d\u0438\u044f\u043c\u0438 \u043e \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 <code>Vue<\/code> \u044f \u043f\u043e\u0434\u0435\u043b\u044e\u0441\u044c \u043a\u0430\u043a-\u043d\u0438\u0431\u0443\u0434\u044c \u0432 \u0434\u0440\u0443\u0433\u043e\u0439 \u0440\u0430\u0437, \u043d\u043e, \u0432 \u0446\u0435\u043b\u043e\u043c, \u043c\u043e\u0433\u0443 \u0441\u043a\u0430\u0437\u0430\u0442\u044c, \u0447\u0442\u043e \u0432\u043f\u0435\u0447\u0430\u0442\u043b\u0435\u043d\u0438\u044f \u043a\u0440\u0430\u0439\u043d\u0435 \u043f\u043e\u043b\u043e\u0436\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 (\u0435\u0441\u0442\u044c \u043c\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u043a\u043e\u043b\u044c\u043d\u044b\u0445 \u043f\u043b\u044e\u0448\u0435\u043a).<\/p>\n<p>  <\/p>\n<h2 id=\"izmerenie-proizvoditelnosti\">\u0418\u0437\u043c\u0435\u0440\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438<\/h2>\n<p>  <\/p>\n<p>\u042f \u043e\u043f\u0438\u0448\u0443 \u0438\u0437\u043c\u0435\u0440\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 Redux-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u043d\u043e \u0442\u043e\u0447\u043d\u043e \u0442\u0430\u043a\u043e\u0439 \u0436\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d \u0432\u043e Vuex-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438.<\/p>\n<p>  <\/p>\n<p>\u042f \u043d\u0435 \u0431\u0443\u0434\u0443 \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043e\u0431\u043e \u0432\u0441\u0435\u0445 \u043c\u0435\u0442\u043e\u0434\u0430\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u044f \u0438\u0441\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u043b. \u041d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0438 \u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u044b\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0437\u0430\u043f\u0438\u0441\u0438 2500 \u0437\u0430\u0434\u0430\u0447 \u0438 \u0438\u0445 \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f.<\/p>\n<p>  <\/p>\n<p>\u041e\u0442\u043a\u043b\u044e\u0447\u0430\u0435\u043c \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0437\u0430\u0434\u0430\u0447 \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ store.dispatch(fetchTodos()).then(() => store.dispatch(giveMeSomeTime()))<\/code><\/pre>\n<p>  <\/p>\n<p>\u0412\u043d\u043e\u0441\u0438\u043c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 <code>App.jsx<\/code>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ \u0425\u0443\u043a \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u0438\u0441\u043f\u0435\u0442\u0447\u0435\u0440\u0430 import { useDispatch } from 'react-redux' \/\/ \u041e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u0434\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u043e\u0432\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438, \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0437\u0430\u0434\u0430\u0447\u0438 \u0438 \u0441\u0435\u043b\u0435\u043a\u0442\u043e\u0440 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0432\u0441\u0435\u0445 \u0437\u0430\u0434\u0430\u0447 import { addTodo, updateTodo, selectAll } from '.\/store' \/\/ \u0423\u0442\u0438\u043b\u0438\u0442\u0430 \u0434\u043b\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u043e\u0432 import { nanoid } from '@reduxjs\/toolkit'<\/code><\/pre>\n<p>  <\/p>\n<p>\u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0432\u0441\u0435 \u0437\u0430\u0434\u0430\u0447\u0438 (\u043e\u043d\u0438 \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u044e\u0442\u0441\u044f \u043d\u0430\u043c \u0434\u043b\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f):<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">const todos = useSelector(selectAll)<\/code><\/pre>\n<p>  <\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0434\u043b\u044f \u0437\u0430\u043f\u0438\u0441\u0438 2500 \u0437\u0430\u0434\u0430\u0447:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">const createManyTodos = () => {  \/\/ \u043c\u0430\u0441\u0441\u0438\u0432 \u0434\u043b\u044f \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0439  const times = []  \/\/ 25 \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u0439  for (let i = 0; i &lt; 25; i++) {    \/\/ \u0432\u0440\u0435\u043c\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438    const start = Date.now()    \/\/ 100 \u0437\u0430\u0434\u0430\u0447    for (let i = 0; i &lt; 100; i++) {      const id = nanoid()      const todo = {        id,        text: `Todo ${id}`,        done: false,        edit: false      }      \/\/ \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044e \u0434\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u043e\u0432\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438      dispatch(addTodo(todo))    }    \/\/ \u0440\u0430\u0437\u043d\u0438\u0446\u0430 \u043c\u0435\u0436\u0434\u0443 \u043d\u0430\u0447\u0430\u043b\u043e\u043c \u0438 \u043e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u0435\u043c \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438    const diff = Date.now() - start    \/\/ \u043f\u043e\u043c\u0435\u0449\u0430\u0435\u043c \u0440\u0430\u0437\u043d\u0438\u0446\u0443 \u0432 \u043c\u0430\u0441\u0441\u0438\u0432    times.push(diff)  }  \/\/ \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u043c \u0441\u0440\u0435\u0434\u043d\u0435\u0435 \u0432\u0440\u0435\u043c\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0439  const time = times.reduce((a, c) => (a += c), 0) \/ 25  \/\/ \u0438 \u0432\u044b\u0432\u043e\u0434\u0438\u043c \u0435\u0433\u043e \u0432 \u043a\u043e\u043d\u0441\u043e\u043b\u044c  console.log(time) }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0434\u043b\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0432\u0441\u0435\u0445 \u0437\u0430\u0434\u0430\u0447:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">const updateAllTodos = () => {  \/\/ \u0432\u0440\u0435\u043c\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438  const start = Date.now()  \/\/ \u043f\u0435\u0440\u0435\u0431\u0438\u0440\u0430\u0435\u043c \u0437\u0430\u0434\u0430\u0447\u0438  for (let i = 0; i &lt; todos.length; i++) {    \/\/ \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044e \u0434\u043b\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0437\u0430\u0434\u0430\u0447\u0438 - \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0438\u043d\u0434\u0438\u043a\u0430\u0442\u043e\u0440\u0430 \u0435\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u043e\u0441\u0442\u0438    dispatch(updateTodo({ id: todos[i].id, changes: { done: true } }))  }  \/\/ \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u043c \u0440\u0430\u0437\u043d\u0438\u0446\u0443 \u043c\u0435\u0436\u0434\u0443 \u043d\u0430\u0447\u0430\u043b\u043e\u043c \u0438 \u043e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u0435\u043c \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438  const diff = Date.now() - start  \/\/ \u0438 \u0432\u044b\u0432\u043e\u0434\u0438\u043c \u0435\u0435 \u0432 \u043a\u043e\u043d\u0441\u043e\u043b\u044c  console.log(diff) }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0432 \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u0443 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u043a\u043d\u043e\u043f\u043a\u0438:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">&lt;div className='d-flex gap-2 mb-2 align-items-center'>  &lt;button className='btn btn-primary' onClick={createManyTodos}>    Create  &lt;\/button>  &lt;p className='mb-0'>many todos&lt;\/p> &lt;\/div> &lt;div className='d-flex gap-2 mb-2 align-items-center'>  &lt;button className='btn btn-primary' onClick={updateAllTodos}>    Update  &lt;\/button>  &lt;p className='mb-0'>all todos&lt;\/p> &lt;\/div><\/code><\/pre>\n<p>  <\/p>\n<p>\u0423 \u0432\u0430\u0441 \u043c\u043e\u0436\u0435\u0442 \u0432\u043e\u0437\u043d\u0438\u043a\u043d\u0443\u0442\u044c \u0432\u043e\u043f\u0440\u043e\u0441 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a\u043e\u0435 \u0432\u043b\u0438\u044f\u043d\u0438\u0435 \u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433 \u0437\u0430\u0434\u0430\u0447 \u043d\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0439. \u041e\u0442\u0432\u0435\u0442: \u0434\u043b\u044f <code>Vuex<\/code> \u043f\u043e\u0447\u0442\u0438 \u043d\u0438\u043a\u0430\u043a\u043e\u0435. \u041d\u043e \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0441 <code>Redux<\/code>, \u043d\u0430 \u043f\u0435\u0440\u0432\u044b\u0439 \u0432\u0437\u0433\u043b\u044f\u0434, \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f, \u0447\u0442\u043e \u043e\u043d \u043e\u0436\u0438\u0434\u0430\u0435\u0442 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0438 \u0432\u0441\u0435\u0445 \u0437\u0430\u0434\u0430\u0447 (\u0434\u0430\u0436\u0435 \u043a\u043e\u0433\u0434\u0430 \u0442\u0430\u043a\u0430\u044f \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0430 \u043e\u0442\u043a\u043b\u044e\u0447\u0435\u043d\u0430), \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442 \u0435\u0433\u043e \u041e\u0427\u0415\u041d\u042c \u043c\u0435\u0434\u043b\u0435\u043d\u043d\u044b\u043c. \u041d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435, \u043a\u0430\u043a \u043c\u044b \u0443\u0432\u0438\u0434\u0438\u043c \u043f\u043e\u0437\u0436\u0435, \u0432\u0441\u0435 \u0441 \u0442\u043e\u0447\u043d\u043e\u0441\u0442\u044c\u044e \u0434\u0430 \u043d\u0430\u043e\u0431\u043e\u0440\u043e\u0442: \u043d\u0435 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433 \u0437\u0430\u043c\u0435\u0434\u043b\u044f\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0443 <code>Redux<\/code>, \u0430 <code>Redux<\/code> \u0431\u043b\u043e\u043a\u0438\u0440\u0443\u0435\u0442 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433.<\/p>\n<p>  <\/p>\n<p>\u042f \u043e\u0431\u043d\u043e\u0432\u0438\u043b \u043a\u043e\u0434 \u0432 <a href=\"https:\/\/github.com\/harryheman\/redux-vs-vuex\">\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438<\/a> \u0438 \u043f\u0435\u0441\u043e\u0447\u043d\u0438\u0446\u0430\u0445, \u0442\u0430\u043a \u0447\u0442\u043e \u043c\u043e\u0436\u0435\u0442\u0435 \u043e\u0446\u0435\u043d\u0438\u0442\u044c \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e.<\/p>\n<p>  <\/p>\n<p>\u041c\u043e\u0438 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0432\u044b\u0433\u043b\u044f\u0434\u044f\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c (\u043e\u043d\u0438 \u043e\u0447\u0435\u043d\u044c \u0441\u0438\u043b\u044c\u043d\u043e \u043c\u0435\u043d\u044f \u0443\u0434\u0438\u0432\u0438\u043b\u0438):<\/p>\n<p>  <\/p>\n<ul>\n<li>\u0432 \u0440\u0435\u0436\u0438\u043c\u0435 \u0434\u043b\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438<br \/> \n<ul>\n<li>\u0437\u0430\u043f\u0438\u0441\u044c \u0437\u0430\u0434\u0430\u0447<\/li>\n<li><code>Redux<\/code> \u2014 <code>400-450<\/code> \u043c\u0441<\/li>\n<li><code>Vuex<\/code> \u2014 <code>4-5<\/code> \u043c\u0441<\/li>\n<li>\u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0437\u0430\u0434\u0430\u0447<\/li>\n<li><code>Redux<\/code> \u2014 \u0447\u0443\u0434\u043e\u0432\u0438\u0449\u043d\u044b\u0435 <code>18000-20000<\/code> \u043c\u0441<\/li>\n<li><code>Vuex<\/code> \u2014 \u0432 \u0440\u0430\u0439\u043e\u043d\u0435 <code>1500<\/code> \u043c\u0441<\/li>\n<\/ul>\n<\/li>\n<li>\u0432 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u043c \u0440\u0435\u0436\u0438\u043c\u0435 (\u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <a href=\"https:\/\/www.npmjs.com\/package\/serve\"><code>serve<\/code><\/a>)<br \/> \n<ul>\n<li>\u0437\u0430\u043f\u0438\u0441\u044c \u0437\u0430\u0434\u0430\u0447<\/li>\n<li><code>Redux<\/code> \u2014 \u0432 \u0441\u0440\u0435\u0434\u043d\u0435\u043c <code>300<\/code> \u043c\u0441<\/li>\n<li><code>Vuex<\/code> \u2014 \u043e\u043a\u043e\u043b\u043e <code>4<\/code> \u043c\u0441<\/li>\n<li>\u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0437\u0430\u0434\u0430\u0447<\/li>\n<li><code>Redux<\/code> \u2014 \u043f\u043e-\u043f\u0440\u0435\u0436\u043d\u0435\u043c\u0443 \u0447\u0443\u0434\u043e\u0432\u0438\u0449\u043d\u044b\u0435 <code>11000-13000<\/code> \u043c\u0441<\/li>\n<li><code>Vuex<\/code> \u2014 \u043a\u0430\u043a \u043d\u0438 \u0441\u0442\u0440\u0430\u043d\u043d\u043e, \u043e\u043a\u043e\u043b\u043e <code>2000<\/code> \u043c\u0441 (<code>-500<\/code> \u043c\u0441 \u043f\u043e \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044e \u0441 \u0440\u0435\u0436\u0438\u043c\u043e\u043c \u0434\u043b\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438)<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043f\u0440\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0438 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0439 \u0437\u0430\u043f\u0438\u0441\u0438 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c <code>Vuex<\/code> \u0432\u044b\u0448\u0435 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438 <code>Redux<\/code> \u0432 <code>70-90<\/code> \u0440\u0430\u0437, \u0430 \u043f\u0440\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0438 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0439 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u2014 \u0432 <code>5-6<\/code> \u0440\u0430\u0437.<\/p>\n<p>  <\/p>\n<p>\u041f\u043e\u043f\u044b\u0442\u0430\u0432\u0448\u0438\u0441\u044c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u043f\u0440\u0438\u0447\u0438\u043d\u0443 \u0442\u0430\u043a\u043e\u0439 \u043c\u0435\u0434\u043b\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 <code>Redux<\/code>, \u044f \u043f\u0440\u0438\u0448\u0435\u043b \u043a \u0432\u044b\u0432\u043e\u0434\u0443, \u0447\u0442\u043e \u0432\u0441\u0435 \u0434\u0435\u043b\u043e \u0432 \u043c\u0430\u043d\u0438\u043f\u0443\u043b\u044f\u0446\u0438\u044f\u0445 \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u043e\u0432\u0435\u0440\u0448\u0430\u0435\u0442 <code>Redux<\/code> \u0441 \u0446\u0435\u043b\u044c\u044e \u0438\u0445 <a href=\"https:\/\/redux.js.org\/usage\/structuring-reducers\/normalizing-state-shape\">\u043d\u043e\u0440\u043c\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438<\/a> \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <a href=\"https:\/\/redux-toolkit.js.org\/api\/createEntityAdapter\">\u0430\u0434\u0430\u043f\u0442\u0435\u0440\u0430 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439<\/a>. \u041f\u0440\u0438\u0447\u0435\u043c, \u0432\u0441\u0435 \u043d\u0430\u0441\u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043b\u043e\u0445\u043e, \u0447\u0442\u043e \u043f\u043e\u043f\u044b\u0442\u043a\u0430 \u0437\u0430\u043f\u0438\u0441\u0438 10 000 \u0437\u0430\u0434\u0430\u0447 &#171;\u0432\u0435\u0448\u0430\u0435\u0442&#187; \u0431\u0440\u0430\u0443\u0437\u0435\u0440 (\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u0432\u0430\u0448\u0430 \u043c\u0430\u0448\u0438\u043d\u0430 \u0441\u0443\u043c\u0435\u0435\u0442 \u0441 \u044d\u0442\u0438\u043c \u0441\u043f\u0440\u0430\u0432\u0438\u0442\u044c\u0441\u044f, \u043c\u043e\u044f \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0447\u0435\u0441\u043a\u0438 \u043e\u0442\u043a\u0430\u0437\u044b\u0432\u0430\u043b\u0430\u0441\u044c \u0441\u043e \u043c\u043d\u043e\u0439 \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u0447\u0430\u0442\u044c). \u0414\u043b\u044f \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f <code>Vuex<\/code> \u043f\u0440\u0435\u043a\u0440\u0430\u0441\u043d\u043e \u0441 \u044d\u0442\u0438\u043c \u0441\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f (<em>\u043e\u0441\u0442\u043e\u0440\u043e\u0436\u043d\u043e<\/em>: \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0430 \u0442\u0430\u043a\u043e\u0433\u043e \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u0437\u0430\u0434\u0430\u0447 \u043c\u043e\u0436\u0435\u0442 \u043e\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f \u043d\u0435\u043f\u043e\u0441\u0438\u043b\u044c\u043d\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0435\u0439 \u0434\u043b\u044f \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430). \u041d\u0430 \u043c\u043e\u0439 \u0432\u0437\u0433\u043b\u044f\u0434, \u0438\u0433\u0440\u0430, \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e, \u043d\u0435 \u0441\u0442\u043e\u0438\u0442 \u0441\u0432\u0435\u0447. \u041d\u043e\u0440\u043c\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b, \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e, \u0431\u044b\u0432\u0430\u044e\u0442 \u0443\u0434\u043e\u0431\u043d\u044b\u043c\u0438 \u0432 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u044f\u0445, \u043d\u043e \u0442\u0430\u043a\u043e\u0435 \u0432\u043b\u0438\u044f\u043d\u0438\u0435 \u043d\u0430 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u0435\u043f\u0440\u0438\u0435\u043c\u043b\u0435\u043c\u044b\u043c.<\/p>\n<p>  <\/p>\n<p>\u041d\u043e \u043d\u0435\u0443\u0436\u0435\u043b\u0438 <code>Vuex<\/code> \u2014 \u044d\u0442\u043e \u043b\u0443\u0447\u0448\u0435\u0435, \u0447\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0438\u0442\u044c Flux-\u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u0441 \u0442\u043e\u0447\u043a\u0438 \u0437\u0440\u0435\u043d\u0438\u044f \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0439 \u0438 \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f?<\/p>\n<p>  <\/p>\n<p>\u041c\u043d\u0435, \u043a\u0430\u043a \u0447\u0435\u043b\u043e\u0432\u0435\u043a\u0443, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0434\u043b\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0432 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c <code>React<\/code>, \u0441\u0442\u0430\u043b\u043e \u0437\u0430 \u043d\u0435\u0433\u043e \u043e\u0431\u0438\u0434\u043d\u043e. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u0440\u0435\u0448\u0438\u043b \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u0430\u0442\u044c \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0445\u0443\u043a\u043e\u0432 <code>useContext<\/code> \u0438 <code>useReducer<\/code>, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043f\u0430\u0440\u043e\u0447\u043a\u0438 \u0442\u0440\u044e\u043a\u043e\u0432:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">import { createContext, useContext, useReducer, useMemo } from 'react' import axios from 'axios'  const SERVER_URL = 'http:\/\/localhost:5000\/todos'  \/\/ \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u044b const SET_TODOS = 'SET_TODOS' const SET_STATUS = 'SET_STATUS' const ADD_TODO = 'ADD_TODO' const UPDATE_TODO = 'UPDATE_TODO' const REMOVE_TODO = 'REMOVE_TODO' const COMPLETE_TODOS = 'COMPLETE_TODOS' const CLEAR_COMPLETED = 'CLEAR_COMPLETED' const SET_FILTER = 'SET_FILTER' const SET_MESSAGE = 'SET_MESSAGE'  \/\/ \u0440\u0435\u0434\u0443\u043a\u0442\u043e\u0440 const reducer = (state, { type, payload }) => {  switch (type) {    case SET_TODOS:      return {        ...state,        todos: payload      }    case SET_STATUS:      return {        ...state,        status: payload      }    case ADD_TODO:      return { ...state, todos: state.todos.concat(payload) }    case UPDATE_TODO:      return {        ...state,        todos: state.todos.map((todo) =>          todo.id === payload.id ? { ...todo, ...payload.changes } : todo        )      }    case REMOVE_TODO:      return {        ...state,        todos: state.todos.filter((todo) => todo.id !== payload)      }    case COMPLETE_TODOS:      return { ...state, todos: state.todos.map((todo) => todo.done === true) }    case CLEAR_COMPLETED:      return {        ...state,        todos: state.todos.filter((todo) => todo.done === true)      }    case SET_FILTER:      return {        ...state,        filter: payload      }    case SET_MESSAGE:      return {        ...state,        message: payload      }    default:      return state  } }  \/\/ \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0430 const giveMeSomeTime = async () =>  await new Promise((resolve) => {    const timerId = setTimeout(() => {      resolve()      clearTimeout(timerId)    }, 2000)  })  \/\/ \u0441\u043e\u0437\u0434\u0430\u0442\u0435\u043b\u044c \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0439 \/\/ \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0434\u0438\u0441\u043f\u0435\u0442\u0447\u0435\u0440 const createActions = (dispatch) => ({  setTodos: (todos) => ({    type: SET_TODOS,    payload: todos  }),  setStatus: (status) => ({    type: SET_STATUS,    payload: status  }),  addTodo: (todo) => ({    type: ADD_TODO,    payload: todo  }),  updateTodo: (payload) => ({    type: UPDATE_TODO,    payload  }),  removeTodo: (todoId) => ({    type: REMOVE_TODO,    payload: todoId  }),  completeTodos: () => ({    type: COMPLETE_TODOS  }),  clearCompleted: () => ({    type: COMPLETE_TODOS  }),  setFilter: (filter) => ({    type: SET_FILTER,    payload: filter  }),  setMessage: (message) => ({    type: SET_MESSAGE,    payload: message  }),  async fetchTodos() {    dispatch(this.setStatus('loading'))     try {      const { data: todos } = await axios(SERVER_URL)       dispatch(this.setTodos(todos))       dispatch(        this.setMessage({ type: 'success', text: 'Todos has been loaded' })      )    } catch (err) {      console.error(err.toJSON())       dispatch(        this.setMessage({          type: 'error',          text: 'Something went wrong. Try again later'        })      )    } finally {      dispatch(this.setStatus('idle'))       await giveMeSomeTime()       dispatch(this.setMessage({}))    }  },  async saveTodos(newTodos) {    dispatch(this.setStatus('loading'))     try {      const { data: existingTodos } = await axios(SERVER_URL)       for (const todo of existingTodos) {        const todoUrl = `${SERVER_URL}\/${todo.id}`         const commonTodo = newTodos.find((_todo) => _todo.id === todo.id)         if (commonTodo) {          if (            !Object.entries(commonTodo).every(              ([key, value]) => value === todo[key]            )          ) {            await axios.put(todoUrl, commonTodo)          }        } else {          await axios.delete(todoUrl)        }      }       for (const todo of newTodos) {        if (!existingTodos.find((_todo) => _todo.id === todo.id)) {          await axios.post(SERVER_URL, todo)        }      }       dispatch(        this.setMessage({ type: 'success', text: 'Todos has been saved' })      )    } catch (err) {      console.error(err.toJSON())       dispatch(        this.setMessage({          type: 'error',          text: 'Something went wrong. Try again later'        })      )    } finally {      dispatch(this.setStatus('idle'))       await giveMeSomeTime()       dispatch(this.setMessage({}))    }  } })  \/\/ \u0441\u043e\u0437\u0434\u0430\u0442\u0435\u043b\u044c \u0441\u0435\u043b\u0435\u043a\u0442\u043e\u0440\u043e\u0432 \/\/ \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 const createSelectors = (state) => ({  selectFilteredTodos() {    const { todos, filter } = state    if (filter === 'all') return todos    return filter === 'active'      ? todos.filter((todo) => !todo.done)      : todos.filter((todo) => todo.done)  },  selectTodoStats() {    const { todos } = state    const { length } = todos     const completed = todos.filter((todo) => todo.done).length    const active = length - completed    const percent = length === 0 ? 0 : Math.round((active \/ length) * 100)     return {      total: length,      completed,      active,      percent    }  } })  \/\/ \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 const initialState = {  todos: [],  status: 'idle',  message: {},  filter: 'all' }  \/\/ \u043a\u043e\u043d\u0442\u0435\u043ac\u0442 const Context = createContext()  \/\/ \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440 export const Provider = ({ children }) => {  const [state, dispatch] = useReducer(reducer, initialState)   \/\/ \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u043c\u0435\u043d\u044f\u0442\u044c\u0441\u044f \u043d\u0435 \u0431\u0443\u0434\u0443\u0442, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0438\u0445 \u043c\u043e\u0436\u043d\u043e \u043c\u0435\u043c\u043e\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c  \/\/ \"\u0441\u0432\u0435\u0436\u0435\u0441\u0442\u044c\" \u0438\u0437\u043c\u0435\u043d\u044f\u0435\u043c\u043e\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0434\u0438\u0441\u043f\u0435\u0442\u0447\u0435\u0440\u043e\u043c  const actions = useMemo(() => createActions(dispatch), [])  \/\/ \u0441\u0435\u043b\u0435\u043a\u0442\u043e\u0440\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0442\u044c\u0441\u044f \u043f\u0440\u0438 \u043a\u0430\u0436\u0434\u043e\u043c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f  const selectors = createSelectors(state)   return (    &lt;Context.Provider value={{ state, dispatch, actions, selectors }}>      {children}    &lt;\/Context.Provider>  ) }  \/\/ \u0445\u0443\u043a \u0434\u043b\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430 export const useAppContext = () => useContext(Context)<\/code><\/pre>\n<p>  <\/p>\n<p>\u042f \u043d\u0435 \u0431\u0443\u0434\u0443 \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442\u044c \u043a\u043e\u0434 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432, \u043e\u043d \u043f\u043e\u0445\u043e\u0436 \u043d\u0430 \u043a\u043e\u0434, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f <code>Redux<\/code>, \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430\u043c\u043d\u043e\u0433\u043e \u043a\u043e\u0440\u043e\u0447\u0435. \u041c\u044b \u043f\u0440\u043e\u0441\u0442\u043e \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u0435\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435, \u0434\u0438\u0441\u043f\u0435\u0442\u0447\u0435\u0440, \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u0438 \u0441\u0435\u043b\u0435\u043a\u0442\u043e\u0440\u044b \u0432 \u043d\u0443\u0436\u043d\u044b\u0445 \u043c\u0435\u0441\u0442\u0430\u0445 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0445\u0443\u043a\u0430 <code>useAppContext<\/code>.<\/p>\n<p>  <\/p>\n<p>\u0414\u0435\u043c\u043e \u044d\u0442\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c <a href=\"https:\/\/codesandbox.io\/s\/react-todo-uqk0h\">\u0437\u0434\u0435\u0441\u044c<\/a>. \u041e\u043d\u043e \u0442\u0430\u043a\u0436\u0435 \u043b\u0435\u0436\u0438\u0442 \u0432 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438.<\/p>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u0438\u0437\u043c\u0435\u0440\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u044f \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u043b \u0442\u0443 \u0436\u0435 \u0442\u0435\u0445\u043d\u0438\u043a\u0443 \u0438 \u043f\u043e\u043b\u0443\u0447\u0438\u043b \u0442\u0430\u043a\u0438\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b:<\/p>\n<p>  <\/p>\n<ul>\n<li>\u0432 \u0440\u0435\u0436\u0438\u043c\u0435 \u0434\u043b\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438<br \/> \n<ul>\n<li>\u0437\u0430\u043f\u0438\u0441\u044c \u2014 \u043e\u043a\u043e\u043b\u043e <code>1<\/code> \u043c\u0441<\/li>\n<li>\u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u2014 \u043e\u043a\u043e\u043b\u043e <code>10<\/code> \u043c\u0441<\/li>\n<\/ul>\n<\/li>\n<li>\u0432 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u043c \u0440\u0435\u0436\u0438\u043c\u0435<br \/> \n<ul>\n<li>\u0437\u0430\u043f\u0438\u0441\u044c \u2014 <code>1<\/code> \u043c\u0441<\/li>\n<li>\u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u2014 <code>5-7<\/code> \u043c\u0441<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043f\u043e \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044e \u0441 <code>Vuex<\/code> \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043f\u0440\u0438\u0440\u043e\u0441\u0442 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438: \u0434\u043b\u044f \u0437\u0430\u043f\u0438\u0441\u0438 \u2014 \u0432 <code>4-5<\/code> \u0440\u0430\u0437, \u0434\u043b\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f (\u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435!) \u2014 \u0432 <code>100-150<\/code> \u0440\u0430\u0437.<\/p>\n<p>  <\/p>\n<p>\u0414\u0430\u043d\u043d\u044b\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u0430\u0441\u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u043c, \u0447\u0442\u043e \u0432\u0440\u0435\u043c\u044f \u0437\u0430\u043f\u0438\u0441\u0438 <code>10000<\/code> \u0437\u0430\u0434\u0430\u0447 \u0442\u0430\u043a\u0436\u0435 \u0441\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0432 \u0441\u0440\u0435\u0434\u043d\u0435\u043c <code>1<\/code> \u043c\u0441, \u043d\u0435 \u0441\u0447\u0438\u0442\u0430\u044f \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433\u0430. \u0427\u0442\u043e \u043a\u0430\u0441\u0430\u0435\u0442\u0441\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e, \u0442\u043e \u043f\u0440\u0438 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0438 <code>Vue<\/code> \u0438 <code>React<\/code>, \u043f\u0435\u0440\u0432\u044b\u0439 \u0441\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u043e\u0439 \u0431\u043e\u043b\u044c\u0448\u043e\u0433\u043e \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 DOM-\u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043b\u0443\u0447\u0448\u0435, \u043d\u043e \u044f \u0431\u044b \u043d\u0435 \u0441\u043a\u0430\u0437\u0430\u043b, \u0447\u0442\u043e \u0440\u0430\u0437\u043d\u0438\u0446\u0430 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0439.<\/p>\n<p>  <\/p>\n<h2 id=\"zaklyuchenie\">\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/h2>\n<p>  <\/p>\n<p>\u041c\u044b \u0441 \u0432\u0430\u043c\u0438 \u043d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0441\u0440\u0430\u0432\u043d\u0438\u043b\u0438 <code>Redux<\/code> \u0438 <code>Vuex<\/code> \u2014 \u0434\u0432\u0430 \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u044b\u0445 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u0432, \u0438 \u0443\u0431\u0435\u0434\u0438\u043b\u0438\u0441\u044c, \u0447\u0442\u043e <code>Redux<\/code> \u2014 \u0434\u0430\u043b\u0435\u043a\u043e \u043d\u0435 \u043b\u0443\u0447\u0448\u0438\u0439 \u0432\u044b\u0431\u043e\u0440 \u043a\u0430\u043a \u0441 \u0442\u043e\u0447\u043a\u0438 \u0437\u0440\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u044b \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c\u043e\u0433\u043e \u0438\u043c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430, \u0442\u0430\u043a \u0438 \u0441 \u0442\u043e\u0447\u043a\u0438 \u0437\u0440\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438.<\/p>\n<p>  <\/p>\n<p>\u041a \u0441\u0447\u0430\u0441\u0442\u044c\u044e, \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0439 <code>React<\/code> \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0432 \u043d\u0430\u0448\u0435 \u0440\u0430\u0441\u043f\u043e\u0440\u044f\u0436\u0435\u043d\u0438\u0435 \u0434\u0440\u0443\u0433\u043e\u0439 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0435\u0441\u043b\u0438 \u043d\u0435 \u043b\u0443\u0447\u0448\u0435, \u0442\u043e \u0443\u0436 \u0442\u043e\u0447\u043d\u043e \u043d\u0435 \u0445\u0443\u0436\u0435 <code>Vuex<\/code>. \u0418\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u044d\u0442\u043e\u0433\u043e \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430 \u043c\u043e\u0436\u043d\u043e \u0441\u0438\u043b\u044c\u043d\u043e \u0443\u043f\u0440\u043e\u0441\u0442\u0438\u0442\u044c, \u043d\u043e \u044d\u0442\u043e \u0442\u0435\u043c\u0430 \u0434\u043b\u044f \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438. \u0414\u043b\u044f \u0441\u0435\u0431\u044f \u044f \u0441\u0434\u0435\u043b\u0430\u043b \u0442\u0430\u043a\u043e\u0439 \u0432\u044b\u0432\u043e\u0434: <em>\u043d\u0430\u043c \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0435 \u043d\u0443\u0436\u0435\u043d <code>Redux<\/code> \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c React-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439<\/em>.<\/p>\n<p>  <\/p>\n<p>\u041d\u0430\u0434\u0435\u044e\u0441\u044c, \u0432\u044b \u043d\u0435 \u0437\u0440\u044f \u043f\u043e\u0442\u0440\u0430\u0442\u0438\u043b\u0438 \u0432\u0440\u0435\u043c\u044f \u0438 \u043d\u0430\u0448\u043b\u0438 \u0434\u043b\u044f \u0441\u0435\u0431\u044f \u0447\u0442\u043e-\u0442\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u0435. \u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044e \u0437\u0430 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u0438 \u0445\u043e\u0440\u043e\u0448\u0435\u0433\u043e \u0434\u043d\u044f!<\/p>\n<p>  <\/p>\n<hr\/>\n<p>  <\/p>\n<p><a href=\"https:\/\/timeweb.com\/ru\/?utm_source=habr&amp;utm_medium=banner&amp;utm_campaign=10S&amp;utm_content=low\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/wo\/qf\/6c\/woqf6cweprtwtuq2m7jch92h5wk.png\" data-src=\"https:\/\/habrastorage.org\/webt\/wo\/qf\/6c\/woqf6cweprtwtuq2m7jch92h5wk.png\"\/><\/a><\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/572248\/\"> https:\/\/habr.com\/ru\/articles\/572248\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w780q1\/webt\/py\/cs\/xn\/pycsxnw-4_owrob4sqtc9gqyabi.jpeg\" data-src=\"https:\/\/habrastorage.org\/webt\/py\/cs\/xn\/pycsxnw-4_owrob4sqtc9gqyabi.jpeg\" data-blurred=\"true\"\/>  <\/p>\n<p>  \u041f\u0440\u0438\u0432\u0435\u0442, \u0434\u0440\u0443\u0437\u044c\u044f!<\/p>\n<p>  <\/p>\n<p>\u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u0432\u0430\u0448\u0435\u043c\u0443 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u044e \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0433\u043e \u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u044f, \u043f\u043e\u0441\u0432\u044f\u0449\u0435\u043d\u043d\u043e\u0433\u043e \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044e <a href=\"https:\/\/redux.js.org\/\"><code>Redux<\/code><\/a> \u0438 <a href=\"https:\/\/next.vuex.vuejs.org\/\"><code>Vuex<\/code><\/a>. \u042d\u0442\u043e \u0432\u0442\u043e\u0440\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u0441\u0442\u0430\u0442\u044c\u0438, \u0432\u043e\u0442 <a href=\"https:\/\/habr.com\/ru\/company\/timeweb\/blog\/566682\/\">\u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043f\u0435\u0440\u0432\u0443\u044e<\/a>.<\/p>\n<p>  <\/p>\n<h2 id=\"vvedenie\">\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435<\/h2>\n<p>  <\/p>\n<p><code>Redux<\/code> \u0438 <code>Vuex<\/code> \u2014 \u044d\u0442\u043e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0445 \u043d\u0430 <a href=\"https:\/\/ru.reactjs.org\/\"><code>React<\/code><\/a> \u0438 <a href=\"https:\/\/vuejs.org\/\"><code>Vue<\/code><\/a>, \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e. \u041a\u0430\u0436\u0434\u0430\u044f \u0438\u0437 \u043d\u0438\u0445 \u043f\u043e-\u0441\u0432\u043e\u0435\u043c\u0443 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0443 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0445 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u0432, \u0438\u0437\u0432\u0435\u0441\u0442\u043d\u0443\u044e \u043f\u043e\u0434 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c <a href=\"https:\/\/facebook.github.io\/flux\/\"><code>Flux<\/code><\/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-388043","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/388043","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=388043"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/388043\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=388043"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=388043"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=388043"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}