{"id":428020,"date":"2024-08-01T15:00:08","date_gmt":"2024-08-01T15:00:08","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=428020"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=428020","title":{"rendered":"<span>Polling vs Websockets (\u0441 \u043f\u0440\u0438\u043c\u0435\u0440\u0430\u043c\u0438 \u043d\u0430 React \u0445\u0443\u043a\u0430\u0445)<\/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-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<h3>\u0412\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u0435<\/h3>\n<p>\u0412 \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 \u0432\u0435\u0431-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u0432 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u0432\u0440\u0435\u043c\u0435\u043d\u0438. \u0421\u0440\u0435\u0434\u0438 \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0451\u043d\u043d\u044b\u0445 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u0432\u044b\u0434\u0435\u043b\u044f\u044e\u0442\u0441\u044f Polling \u0438 WebSockets. \u041e\u0431\u0430 \u043f\u043e\u0434\u0445\u043e\u0434\u0430 \u0438\u043c\u0435\u044e\u0442 \u0441\u0432\u043e\u0438 \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0435 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u0438 \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f, \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442 \u0438\u0445 \u043f\u043e\u0434\u0445\u043e\u0434\u044f\u0449\u0438\u043c\u0438 \u0434\u043b\u044f \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0435\u0432. \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u0440\u0430\u0437\u043b\u0438\u0447\u0438\u044f \u043c\u0435\u0436\u0434\u0443 Polling \u0438 WebSockets, \u0438\u0445 \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430 \u0438 \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043a\u0438, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0438\u0437 \u043d\u0438\u0445 \u0432 React \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445 \u043d\u0430 \u0445\u0443\u043a\u0430\u0445.<\/p>\n<h3>Polling<\/h3>\n<p><strong>Polling<\/strong> \u2013 \u044d\u0442\u043e \u043c\u0435\u0442\u043e\u0434, \u043f\u0440\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043a\u043b\u0438\u0435\u043d\u0442 \u043f\u0435\u0440\u0438\u043e\u0434\u0438\u0447\u0435\u0441\u043a\u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445. \u042d\u0442\u043e\u0442 \u043f\u043e\u0434\u0445\u043e\u0434 \u043f\u0440\u043e\u0441\u0442 \u0432 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438, \u043d\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043d\u0435\u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u0435\u043d \u043f\u0440\u0438 \u0447\u0430\u0441\u0442\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u0445, \u0442\u0430\u043a \u043a\u0430\u043a \u043e\u043d \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0432\u0430\u0435\u0442 \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0443 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 \u0438 \u0441\u0435\u0442\u044c.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/423\/87b\/931\/42387b931485c80c0562a463eeca1a9f.png\" alt=\"Untitled\" width=\"1054\" height=\"1452\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/423\/87b\/931\/42387b931485c80c0562a463eeca1a9f.png\"\/><\/p>\n<div><figcaption>Untitled<\/figcaption><\/div>\n<\/figure>\n<p>\u0420\u0435\u0444\u0435\u0442\u0447 \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442\u044c \u043f\u0440\u0438 \u043d\u0430\u0436\u0430\u0442\u0438\u0438 \u043a\u043d\u043e\u043f\u043a\u0438, \u043f\u043e \u0438\u0441\u0442\u0435\u0447\u0435\u043d\u0438\u044e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0433\u043e \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u0432\u0440\u0435\u043c\u0435\u043d\u0438, \u0438\u043b\u0438 \u043f\u0440\u0438 \u043b\u044e\u0431\u043e\u043c \u0434\u0440\u0443\u0433\u043e\u043c \u0441\u043e\u0431\u044b\u0442\u0438\u0438.<\/p>\n<h3>WebSockets<\/h3>\n<p><strong>WebSockets<\/strong> \u2013 \u044d\u0442\u043e \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e\u0435 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u043c\u0435\u0436\u0434\u0443 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u043c \u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c. \u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u044d\u0442\u043e\u043c\u0443 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044e \u0434\u0430\u043d\u043d\u044b\u0435 \u043c\u043e\u0433\u0443\u0442 \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c\u0441\u044f \u0432 \u043e\u0431\u043e\u0438\u0445 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f\u0445 \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u0432\u0440\u0435\u043c\u0435\u043d\u0438, \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442 WebSockets \u0431\u043e\u043b\u0435\u0435 \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u044b\u043c \u0434\u043b\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u0442\u0440\u0435\u0431\u0443\u044e\u0449\u0438\u0445 \u043c\u0433\u043d\u043e\u0432\u0435\u043d\u043d\u043e\u0433\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/f84\/b19\/ca4\/f84b19ca4bef636bab50466cbf65cee2.png\" alt=\"Untitled\" width=\"1688\" height=\"1196\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/f84\/b19\/ca4\/f84b19ca4bef636bab50466cbf65cee2.png\"\/><\/p>\n<div><figcaption>Untitled<\/figcaption><\/div>\n<\/figure>\n<p>\u041a\u043b\u0438\u0435\u043d\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441, \u0430 \u0441\u0435\u0440\u0432\u0435\u0440 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0435\u043c\u0443 handshake, \u043f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442\u0441\u044f websocket \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u043c\u043e\u043c\u0435\u043d\u0442\u0430\u043b\u044c\u043d\u043e \u043f\u0440\u0438\u0445\u043e\u0434\u044f\u0442 \u043e\u0442 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0434\u043e \u0441\u0435\u0440\u0432\u0435\u0440\u0430, \u0438 \u043d\u0430\u043e\u0431\u043e\u0440\u043e\u0442.<\/p>\n<h3>\u0420\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043e\u0431\u043e\u0438\u0445 \u043f\u043e\u0434\u0445\u043e\u0434\u043e\u0432<\/h3>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c 2 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f: \u0432 \u043f\u0435\u0440\u0432\u043e\u043c \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0447\u0430\u0442 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u043f\u043e\u043b\u043b\u0438\u043d\u0433\u0430, \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e \u043a\u043d\u043e\u043f\u043a\u0443 \u201c\u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c\u201d, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442\u044c \u0440\u0435\u0444\u0435\u0442\u0447; \u0432\u043e \u0432\u0442\u043e\u0440\u043e\u043c \u0436\u0435 \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u0447\u0430\u0442 \u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c web socket \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435, \u0434\u043b\u044f \u043c\u043e\u043c\u0435\u043d\u0442\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<h3>\u0417\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438<\/h3>\n<p>\u0414\u043b\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0437\u0430\u0434\u0443\u043c\u043a\u0438 \u043c\u043d\u0435 \u043f\u0440\u0438\u0433\u043e\u0434\u0438\u0442\u0441\u044f \u0432\u0441\u0435\u0433\u043e 2 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438:<\/p>\n<ul>\n<li>\n<p><a href=\"https:\/\/ui.shadcn.com\/\" rel=\"noopener noreferrer nofollow\">shadcn\/ui<\/a> &#8212; \u0434\u043b\u044f \u043a\u0440\u0430\u0441\u0438\u0432\u044b\u0445 ui \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/siberiacancode.github.io\/reactuse\/\" rel=\"noopener noreferrer nofollow\">reactuse<\/a> &#8212; \u043b\u0443\u0447\u0448\u0430\u044f \u0443\u0442\u0438\u043b\u0438\u0442\u0430\u0440\u043d\u0430\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0441 \u043e\u0433\u0440\u043e\u043c\u043d\u044b\u043c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e\u043c \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0445 react \u0445\u0443\u043a\u043e\u0432 (\u043c\u044b \u0432\u043e\u0437\u044c\u043c\u0435\u043c \u043e\u0442\u0442\u0443\u0434\u0430 useQuery \u0438 useWebsocket)<\/p>\n<\/li>\n<\/ul>\n<p>\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0438 \u043d\u0443\u0436\u043d\u044b\u0435 \u043d\u0430\u043c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0438\u0437 ui \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 (\u044d\u0442\u043e \u043d\u0430\u0447\u0430\u043b\u043e \u0431\u0443\u0434\u0435\u0442 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u043c \u0434\u043b\u044f \u043e\u0431\u043e\u0438\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439)<\/p>\n<pre><code class=\"bash\">$yarn add @siberiacancode\/reactuse $yarn add tailwindcss $npx tailwindcss init $npx shadcn-ui@latest init $npx shadcn-ui@latest add button card input <\/code><\/pre>\n<p>\u0414\u043b\u044f \u043e\u0431\u043e\u0438\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0447\u0430\u0442\u0430. \u041d\u0430\u0447\u043d\u0435\u043c \u0441 \u043e\u0431\u044b\u0447\u043d\u043e\u0439 \u0432\u0435\u0440\u0441\u0442\u043a\u0438. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c \u0438\u0437 shadcn\/ui \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b: button, input, scroll-area, separator. (\u0441\u043c. \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044e, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043a\u0430\u043a \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b)<\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u043a\u0443 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 Chat:<\/p>\n<pre><code class=\"typescript\">import { Button } from \".\/ui\/button\"; import { Card, CardContent, CardTitle } from \".\/ui\/card\"; import { Input } from \".\/ui\/input\"; import { ScrollArea } from \".\/ui\/scroll-area\"; import { Separator } from \".\/ui\/separator\"; const Chat = () =&gt; { return ( &lt;Card className=\" w-80 h-96\"&gt; &lt;CardTitle&gt; &lt;div className=\"p-2\"&gt;Chat&lt;\/div&gt; &lt;Separator \/&gt; &lt;\/CardTitle&gt; &lt;CardContent className=\"p-0 flex flex-col\"&gt; &lt;ScrollArea className=\" w-full h-72\"&gt; &lt;div className=\" p-2\"&gt; &lt;div className=\"flex\"&gt; &lt;div className=\" bg-slate-300 text-background rounded-md p-1.5 max-w-64 shadow-slate-300 shadow-md\"&gt; Message to you &lt;\/div&gt; &lt;\/div&gt; &lt;div className=\"flex justify-end\"&gt; &lt;div className=\" bg-slate-800 text-foreground rounded-md p-1.5 max-w-64 shadow-slate-800 shadow-md\"&gt; Message from you &lt;\/div&gt; &lt;\/div&gt; &lt;\/div&gt; &lt;\/ScrollArea&gt; &lt;div className=\" flex \"&gt; &lt;Input placeholder=\"Your message...\" className=\"\" \/&gt; &lt;Button className=\"\"&gt;Send&lt;\/Button&gt; &lt;\/div&gt; &lt;\/CardContent&gt; &lt;\/Card&gt; ); }; export default Chat; <\/code><\/pre>\n<p>\u041f\u043e\u043b\u0443\u0447\u0438\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 ui:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/fde\/a37\/3b0\/fdea373b0d48c5fb41e5c3cbafdbbb0a.png\" alt=\"Untitled\" width=\"974\" height=\"1024\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/fde\/a37\/3b0\/fdea373b0d48c5fb41e5c3cbafdbbb0a.png\"\/><\/p>\n<div><figcaption>Untitled<\/figcaption><\/div>\n<\/figure>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u043c type Message:<\/p>\n<pre><code class=\"typescript\">type Message = {   text: string;   type: \"client\" | \"server\"; }; <\/code><\/pre>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 <em>messages,<\/em> \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0431\u0443\u0434\u0435\u043c \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432\u0441\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f:<\/p>\n<pre><code class=\"typescript\">import { useState } from \"react\"; <\/code><\/pre>\n<pre><code class=\"typescript\">const messages = useState&lt;Message[]&gt;([]) <\/code><\/pre>\n<p>\u041d\u0435\u043c\u043d\u043e\u0433\u043e \u043f\u043e\u043c\u0435\u043d\u044f\u0435\u043c \u0432\u0435\u0440\u0441\u0442\u043a\u0443, \u0447\u0442\u043e\u0431\u044b \u0432 \u0447\u0430\u0442\u0435 \u043e\u0442\u043e\u0431\u0440\u043e\u0436\u0430\u043b\u0438\u0441\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0438\u0437 \u0441\u0442\u044d\u0439\u0442\u0430 messages \u0438 \u043d\u0430 \u043d\u0438\u0445 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u043b\u0438\u0441\u044c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0435 \u0441\u0442\u0438\u043b\u0438, \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0438 \u0441 \u0442\u0435\u043c, \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043b\u0438 \u0442\u0438\u043f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u201cserver\u201d \u0438\u043b\u0438 \u201cclient\u201d<\/p>\n<pre><code class=\"typescript\">&lt;ScrollArea className=\" w-full h-72\"&gt;   &lt;div className=\"p-2\"&gt;     {messages.map((message, index) =&gt; {       if (message.type === \"client\")         return (           &lt;div className=\"flex justify-end\" key={index}&gt;             &lt;div className=\" bg-slate-800 text-foreground rounded-md p-1.5 max-w-64 shadow-slate-800 shadow-md\"&gt;               {message.text}             &lt;\/div&gt;           &lt;\/div&gt;         );       else         return (           &lt;div className=\"flex\"&gt;             &lt;div className=\" bg-slate-300 text-background rounded-md p-1.5 max-w-64 shadow-slate-300 shadow-md\"&gt;               {message.text}             &lt;\/div&gt;           &lt;\/div&gt;         );     })}   &lt;\/div&gt; &lt;\/ScrollArea&gt;; <\/code><\/pre>\n<h4>\u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0445\u0443\u043a \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043f\u043e\u043b\u044f\u043c\u0438 \u0432\u0432\u043e\u0434\u0430<\/h4>\n<p><strong>useField &#8212;<\/strong> \u044d\u0442\u043e\u0442 \u0445\u0443\u043a \u0438\u0437 \u043f\u0430\u043a\u0435\u0442\u0430 <em>reactuse<\/em> \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u043d\u043e\u0433\u043e \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0441\u0442\u0432\u0438\u044f \u0441 \u043f\u043e\u043b\u044f\u043c\u0438 \u0432\u0432\u043e\u0434\u0430.<\/p>\n<pre><code class=\"typescript\">const messageInput = useField({initialValue: ''}) <\/code><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u043c\u044b \u0437\u0430\u0434\u0430\u043b\u0438 initialValue, \u0440\u0430\u0432\u043d\u043e\u0435 \u043f\u0443\u0441\u0442\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0435. \u0414\u0430\u043b\u0435\u0435 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u043a messageInput, \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u043f\u043e\u043b\u0435\u043c \u0432\u0432\u043e\u0434\u0430.<\/p>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u043c \u043a \u043d\u0430\u0448\u0435\u043c\u0443 \u0438\u043d\u043f\u0443\u0442\u0443 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435:<\/p>\n<pre><code class=\"typescript\">&lt;Input placeholder=\"Your message...\" {...messageInput.register()} \/&gt; <\/code><\/pre>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043c\u044b \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u043c \u0438 \u043f\u0440\u0438\u0432\u044f\u0437\u044b\u0432\u0430\u0435\u043c \u0445\u0443\u043a \u043a \u044d\u0442\u043e\u043c\u0443 \u043f\u043e\u043b\u044e \u0432\u0432\u043e\u0434\u0430<\/p>\n<h4>1 &#8212; \u041c\u0435\u0442\u043e\u0434 Polling<\/h4>\n<p>\u0414\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0438\u0437 \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u0432 \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u044c\u0441\u044f \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0441\u0432\u043e\u0439 \u043c\u043e\u043a\u043e\u0432\u044b\u0439 \u0441\u0435\u0440\u0432\u0435\u0440. \u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u0441 polling \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0441\u044c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u043e\u0439 \u043e\u0442 \u0441\u043e\u0437\u0434\u0430\u0442\u0438\u043b\u044f reactuse &#8212; <a href=\"https:\/\/www.npmjs.com\/package\/mock-config-server\" rel=\"noopener noreferrer nofollow\"><strong>? Mock Config Server<\/strong><\/a><\/p>\n<p>\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c \u043f\u0430\u043a\u0435\u0442:<\/p>\n<pre><code class=\"bash\">$yarn add mock-config-server --dev <\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u0434\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e \u043f\u0430\u043a\u0435\u0442\u0430. \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0444\u0430\u0439\u043b <em>mock-server.config.js:<\/em><\/p>\n<pre><code class=\"javascript\">\/** @type {import('mock-config-server').MockServerConfig} *\/  let messages = [];  const mockServerConfig = {   rest: {     baseUrl: \"\/api\",     configs: [       {         path: \"\/messages\",         method: \"get\",         routes: [{ data: messages }],       },       {         path: \"\/messages\/new\",         method: \"post\",         routes: [{ data: { success: \"true\" } }],         interceptors: {           response: (data, { request }) =&gt; {             messages.push({               text: request.body.text,               type: \"client\",             });             messages.push({               text: request.body.text,               type: \"server\",             });              return data;           },         },       },     ],   }, };  export default mockServerConfig; <\/code><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e <em>messages<\/em>. \u0412 \u043d\u0435\u0439 \u0431\u0443\u0434\u0435\u043c \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432\u0441\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f. \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043c\u0430\u0440\u0448\u0440\u0443\u0442 \/messages \u0438 \u0437\u0430\u043f\u0440\u043e\u0441 GET. \u042d\u0442\u043e\u0442 \u0437\u0430\u043f\u0440\u043e\u0441 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0441\u0442\u043e \u043e\u0442\u0434\u0430\u0432\u0430\u0442\u044c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e messages, \u0440\u0430\u0432\u043d\u0443\u044e \u0432\u0441\u0435\u043c \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u043c \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u044b\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f\u043c \u0432 \u043c\u0430\u0441\u0441\u0438\u0432\u0435. \u0414\u0430\u043b\u0435\u0435 POST \u0437\u0430\u043f\u0440\u043e\u0441 \/messages\/new. \u0427\u0435\u0440\u0435\u0437 <em>interceptors<\/em> \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u043a\u043e\u0433\u0434\u0430 \u043f\u0440\u0438\u0434\u0435\u0442 \u044d\u0442\u043e\u0442 \u0437\u0430\u043f\u0440\u043e\u0441. \u0412 \u044d\u0442\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043c\u044b \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u043c \u0442\u0435\u043a\u0441\u0442 \u0438\u0437 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0432 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e <em>messages<\/em> 2 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0441 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u043c \u0442\u0435\u043a\u0441\u0442\u043e\u043c: \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0438 \u043e\u0442 \u043a\u043b\u0438\u0435\u043d\u0442\u0430.<\/p>\n<p>\u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u043c\u043e\u043a\u043e\u0432\u043e\u0433\u043e \u044d\u0445\u043e-\u0447\u0430\u0442 \u0430\u043f\u0438 \u0433\u043e\u0442\u043e\u0432\u0430! \u0417\u0430\u043f\u0443\u0441\u0442\u0438\u043c \u0441\u0435\u0440\u0432\u0435\u0440:<\/p>\n<pre><code class=\"bash\"> npx mock-config-server <\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0432\u0441\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u043f\u043e <a href=\"http:\/\/localhost:31299\" rel=\"noopener noreferrer nofollow\">http:\/\/localhost:31299<\/a>\/api<\/p>\n<p>\u0412\u0435\u0440\u043d\u0435\u043c\u0441\u044f \u043a \u0431\u0430\u0437\u043e\u0432\u043e\u0439 \u0432\u0435\u0440\u0441\u0442\u043a\u0435:<\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0437\u0430\u043f\u0440\u043e\u0441 \u0437\u0430 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0445\u0443\u043a\u0430 useQuery:<\/p>\n<pre><code class=\"typescript\">import { useField, useQuery, useMutation } from \"@siberiacancode\/reactuse\"; <\/code><\/pre>\n<pre><code class=\"typescript\">const { data, refetch, isRefetching, isLoading, isError, error } = useQuery(   () =&gt; fetch(\"&lt;http:\/\/localhost:31299\/api\/messages&gt;\").then((res) =&gt; res.json()),   {     refetchInterval: 1200000,     keys: [\"messages\"],     onSuccess: (data) =&gt; setMessages(data),   } ); <\/code><\/pre>\n<p>\u0412 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c callback \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0438 \u043e\u0431\u044a\u0435\u043a\u0442 options. \u0412 \u043d\u0435\u043c \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u043a\u043b\u044e\u0447,  <em>refetchInterval,<\/em> \u0447\u0442\u043e\u0431\u044b \u0437\u0430\u043f\u0440\u043e\u0441 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u043b\u0441\u044f \u0437\u0430\u043d\u043e\u0432\u043e \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0447\u0435\u0440\u0435\u0437 120000 \u043c\u0438\u043b\u0438\u0441\u0435\u043a\u0443\u043d\u0434 (20 \u043c\u0438\u043d\u0443\u0442) \u0438 <em>onSuccess &#8212;<\/em> \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0443\u0441\u043f\u0435\u0445\u0430 **\u043f\u0440\u0438\u0441\u0432\u043e\u0438\u043c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 (data) \u0441\u0442\u044d\u0439\u0442\u0443 <em>messages<\/em>. \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0440\u044f\u0434 \u0441\u0442\u044d\u0439\u0442\u043e\u0432 \u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u044b \u0437\u0430\u044e\u0437\u0430\u0435\u043c \u043f\u043e\u0437\u0436\u0435.<\/p>\n<p>\u041d\u0435\u043c\u043d\u043e\u0433\u043e \u043f\u043e\u043c\u0435\u043d\u044f\u0435\u043c \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u043a\u0443 \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u0430 \u043a\u0430\u0440\u0442\u043e\u0447\u043a\u0438:<\/p>\n<pre><code class=\"typescript\">&lt;ScrollArea className=\" w-full h-72\"&gt;   &lt;div className=\"p-2\"&gt;     {isLoading || isRefetching ? (       &lt;p className=\"text-center\"&gt;Wait...&lt;\/p&gt;     ) : isError ? (       &lt;p className=\"text-center\"&gt;Error {error?.message}&lt;\/p&gt;     ) : (       messages.map((message, index) =&gt; {         if (message.type === \"client\")           return (             &lt;div className=\"flex justify-end\" key={index}&gt;               &lt;div className=\" bg-slate-800 text-foreground rounded-md p-1.5 max-w-64 shadow-slate-800 shadow-md\"&gt;                 {message.text}               &lt;\/div&gt;             &lt;\/div&gt;           );         else           return (             &lt;div className=\"flex\" key={index}&gt;               &lt;div className=\" bg-slate-300 text-background rounded-md p-1.5 max-w-64 shadow-slate-300 shadow-md\"&gt;                 {message.text}               &lt;\/div&gt;             &lt;\/div&gt;           );       })     )}   &lt;\/div&gt; &lt;\/ScrollArea&gt;; <\/code><\/pre>\n<p>\u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u0448\u0438\u0431\u043a\u0438 \u043e\u0442\u043e\u0431\u0440\u0430\u0437\u0438\u043c \u043e\u0448\u0438\u0431\u043a\u0443, \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0438\u043b\u0438 \u0440\u0435\u0444\u0435\u0442\u0447\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u043c Wait\u2026 \u0418\u043d\u0430\u0447\u0435 &#8212; \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u043c ui<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0437\u0430\u0439\u043c\u0435\u043c\u0441\u044f \u0440\u0435\u0444\u0435\u0442\u0447\u0435\u043c \u043f\u043e \u043a\u043d\u043e\u043f\u043a\u0435. \u041f\u0440\u043e\u0441\u0442\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043a \u043a\u043d\u043e\u043f\u043a\u0435 Refetch \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435:<\/p>\n<pre><code class=\"typescript\">&lt;Button onClick={()=&gt;refetch()}&gt;Refetch&lt;\/Button&gt; <\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0440\u0438 \u043d\u0430\u0436\u0430\u0442\u0438\u0438 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442\u044c \u0440\u0435\u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0431\u0443\u0434\u0435\u043c \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f.<\/p>\n<pre><code class=\"typescript\">const { mutateAsync } = useMutation(async (text) =&gt; {     await fetch(\"&lt;http:\/\/localhost:31299\/api\/messages\/new&gt;\", {       method: \"POST\",       body: JSON.stringify({ text: text }),       headers: {         Accept: \"application\/json\",         \"Content-Type\": \"application\/json\",       },     });   }); <\/code><\/pre>\n<p>\u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e <em>mutateAsync<\/em> \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u044f \u0445\u0443\u043a <em>useMutation<\/em>.  \u0412 callback \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c POST \u0437\u0430\u043f\u0440\u043e\u0441 \u0441 body \u0438 \u0437\u0430\u0433\u0430\u043b\u043e\u0432\u043a\u0430\u043c\u0438.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0432\u044b\u0437\u0432\u0430\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e <em>mutateAsync<\/em> \u0447\u0442\u043e\u0431\u044b \u0441\u043e\u0432\u0435\u0440\u0448\u0438\u0442\u044c \u043c\u0443\u0442\u0430\u0446\u0438\u044e \u0434\u0430\u043d\u043d\u044b\u0445 (\u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435). \u0412\u044b\u0437\u044b\u0432\u0435\u043c \u0435\u0435 \u043a\u0430\u043a \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043d\u0430\u0436\u043c\u0435\u0442 Send. \u041f\u043e\u0441\u043b\u0435 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0440\u0435\u0441\u0435\u0442\u043d\u0435\u043c \u0444\u043e\u0440\u043c\u0443<\/p>\n<pre><code class=\"typescript\">&lt;Button   onClick={async () =&gt; {     await mutateAsync(messageInput.getValue());     messageInput.reset();   }} &gt;   Send &lt;\/Button&gt;; <\/code><\/pre>\n<p>\u0413\u043e\u0442\u043e\u0432\u043e!<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/339\/261\/e2f\/339261e2f69f3e5eff9932f5ac9b285c.png\" alt=\"Untitled\" width=\"682\" height=\"864\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/339\/261\/e2f\/339261e2f69f3e5eff9932f5ac9b285c.png\"\/><\/p>\n<div><figcaption>Untitled<\/figcaption><\/div>\n<\/figure>\n<p>\u0412\u0435\u0441\u044c \u043a\u043e\u0434:<\/p>\n<pre><code class=\"typescript\">import { useState } from \"react\"; import { Button } from \".\/ui\/button\"; import { Card, CardContent, CardTitle } from \".\/ui\/card\"; import { Input } from \".\/ui\/input\"; import { ScrollArea } from \".\/ui\/scroll-area\"; import { Separator } from \".\/ui\/separator\"; import { useField, useQuery, useMutation } from \"@siberiacancode\/reactuse\";  type Message = {   text: string;   type: \"client\" | \"server\"; };  const Chat = () =&gt; {   const [messages, setMessages] = useState&lt;Message[]&gt;([]);   const messageInput = useField({ initialValue: \"\" });   const { data, refetch, isRefetching, isLoading, isError, error } = useQuery(     () =&gt;       fetch(\"http:\/\/localhost:31299\/api\/messages\").then((res) =&gt; res.json()),     {       refetchInterval: 1200000,       keys: [\"messages\"],       onSuccess: (data) =&gt; setMessages(data),     }   );   const { mutateAsync } = useMutation(async (text) =&gt; {     await fetch(\"http:\/\/localhost:31299\/api\/messages\/new\", {       method: \"POST\",       body: JSON.stringify({ text: text }),       headers: {         Accept: \"application\/json\",         \"Content-Type\": \"application\/json\",       },     });   });    return (     &lt;Card className=\" w-80 h-96\"&gt;       &lt;CardTitle&gt;         &lt;div className=\"p-2 flex justify-between items-center\"&gt;           &lt;p&gt;Pokemon Chat&lt;\/p&gt;           &lt;Button onClick={() =&gt; refetch()}&gt;Refetch&lt;\/Button&gt;         &lt;\/div&gt;         &lt;Separator \/&gt;       &lt;\/CardTitle&gt;       &lt;CardContent className=\"p-0 flex flex-col\"&gt;         &lt;ScrollArea className=\" w-full h-72\"&gt;           &lt;div className=\"p-2\"&gt;             {isLoading || isRefetching ? (               &lt;p className=\"text-center\"&gt;Wait...&lt;\/p&gt;             ) : isError ? (               &lt;p className=\"text-center\"&gt;Error {error?.message}&lt;\/p&gt;             ) : (               messages.map((message, index) =&gt; {                 if (message.type === \"client\")                   return (                     &lt;div className=\"flex justify-end\" key={index}&gt;                       &lt;div className=\" bg-slate-800 text-foreground rounded-md p-1.5 max-w-64 shadow-slate-800 shadow-md\"&gt;                         {message.text}                       &lt;\/div&gt;                     &lt;\/div&gt;                   );                 else                   return (                     &lt;div className=\"flex\" key={index}&gt;                       &lt;div className=\" bg-slate-300 text-background rounded-md p-1.5 max-w-64 shadow-slate-300 shadow-md\"&gt;                         {message.text}                       &lt;\/div&gt;                     &lt;\/div&gt;                   );               })             )}           &lt;\/div&gt;         &lt;\/ScrollArea&gt;         &lt;div className=\" flex \"&gt;           &lt;Input placeholder=\"Your message...\" {...messageInput.register()} \/&gt;           &lt;Button             onClick={async () =&gt; {               await mutateAsync(messageInput.getValue());               messageInput.reset();             }}           &gt;             Send           &lt;\/Button&gt;         &lt;\/div&gt;       &lt;\/CardContent&gt;     &lt;\/Card&gt;   ); };  export default Chat; <\/code><\/pre>\n<h4>\u041c\u0435\u0442\u043e\u0434 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c WebSockets<\/h4>\n<p>\u041a\u0430\u043a \u0438 \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0441 \u043c\u0435\u0442\u043e\u0434\u043e\u043c \u043f\u043e\u043b\u043b\u0438\u043d\u0433\u0430 \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043c\u043e\u043a\u043e\u0432\u044b\u0439 \u0441\u0435\u0440\u0432\u0435\u0440, \u0447\u0442\u043e\u0431\u044b \u0438\u043c\u0438\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0439 \u0431\u044d\u043a\u0435\u043d\u0434. \u0415\u0441\u043b\u0438 \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0441 \u043f\u043e\u043b\u043b\u0438\u043d\u0433\u043e\u043c \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0438 mock-config-server, \u0438 \u0437\u0430\u0434\u0430\u0432\u0430\u043b\u0438 \u0435\u043c\u0443 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b \u044d\u0445\u043e \u0447\u0430\u0442\u0430, \u0442\u043e \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0441 \u0432\u0435\u0431\u0441\u043e\u043a\u0435\u0442\u0430\u043c\u0438 \u0432\u0441\u0435 \u043f\u043e\u043f\u0440\u043e\u0449\u0435, \u0442\u0430\u043a \u043a\u0430\u043a \u043e\u0434\u0438\u043d \u0438\u0437 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0435\u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0432\u0435\u0431\u0441\u043e\u043a\u0435\u0442\u043e\u0432 &#8212; \u044d\u0442\u043e \u0447\u0430\u0442\u044b, \u0442\u043e \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0442 \u0433\u043e\u0442\u043e\u0432\u044b\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u043e \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e.<\/p>\n<p><em>wss:\/\/echo.websocket.org &#8212;<\/em> \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u043f\u043e \u044d\u0442\u043e\u043c\u0443 \u0437\u0430\u043f\u0440\u043e\u0441\u0443, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043a weboscket \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044e.<\/p>\n<p>\u0412\u0435\u0440\u043d\u0435\u043c\u0441\u044f \u043a \u043d\u0430\u0448\u0435\u0439 \u0431\u0430\u0437\u043e\u0432\u043e\u0439 \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u043a\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 Chat. \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043a \u0432\u0435\u0431\u0441\u043e\u043a\u0435\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0443:<\/p>\n<pre><code class=\"typescript\">import { useField, useWebSocket, useMount } from \"@siberiacancode\/reactuse\"; <\/code><\/pre>\n<pre><code class=\"typescript\">const { send, status, close, open } = useWebSocket(     \"wss:\/\/echo.websocket.org\",     {       onConnected: (webSocket) =&gt; console.log(`Connected to ${webSocket.url}`),     }   ); useMount(() =&gt; console.log(\"Connecting to websocket server...\")); <\/code><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u043c\u044b \u0437\u0430\u0434\u0430\u043b\u0438 \u0431\u0430\u0437\u043e\u0432\u0443\u044e \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e \u0438 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0445\u0443\u043a\u0430. \u041f\u0435\u0440\u0435\u0434\u0430\u043b\u0438 \u0430\u0434\u0440\u0435\u0441, \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u043d\u0443\u0436\u043d\u043e \u0437\u0430\u043a\u043e\u043d\u043d\u0435\u043a\u0442\u0438\u0442\u044c\u0441\u044f \u0438 \u0432 options \u0443\u043a\u0430\u0437\u0430\u043b\u0438, \u0447\u0442\u043e \u043a\u043e\u0433\u0434\u0430 \u043f\u0440\u043e\u0438\u0437\u043e\u0439\u0434\u0435\u0442 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 <em>onConnected<\/em>, \u043c\u044b \u0432\u044b\u0432\u0435\u0434\u0435\u043c \u0432 \u043a\u043e\u043d\u0441\u043e\u043b\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043e\u0431 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u043c \u043f\u0440\u0438\u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0438 \u043a \u0441\u0435\u0440\u0432\u0435\u0440\u0443.<\/p>\n<p>\u0422\u0430\u043a\u0436\u0435 \u043d\u0438\u0436\u0435 \u0432\u044b\u0437\u044b\u0432\u0435\u043c \u0445\u0443\u043a <em>useMount<\/em>, \u043e\u043d \u0431\u0443\u0434\u0435\u0442 \u043a\u0438\u0434\u0430\u0442\u044c \u0432 \u043a\u043e\u043d\u0441\u043e\u043b\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 <em>Connecting\u2026<\/em> \u043a\u0430\u043a \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0431\u0443\u0434\u0435\u0442 \u0432\u043f\u0435\u0440\u0432\u044b\u0435 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u0442\u044c\u0441\u044f.<\/p>\n<p><em>(\u0434\u0430\u043b\u0435\u0435 \u043c\u044b \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u043c options \u0443 \u0445\u0443\u043a\u0430 useWebsocket)<\/em><\/p>\n<p>\u041f\u043e\u043c\u0435\u043d\u044f\u0435\u043c \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u043a\u043d\u043e\u043f\u043a\u0438. \u041d\u0430 \u043a\u043b\u0438\u043a \u043e\u043d\u0430 \u0431\u0443\u0434\u0435\u0442 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435:<\/p>\n<pre><code class=\"typescript\">          &lt;Button             onClick={() =&gt; {               const message = messageInput.getValue();               setMessages((prevMessages) =&gt; [                 ...prevMessages,                 { text: message, type: \"client\" },               ]);               send(message);               messageInput.reset();             }}           &gt; <\/code><\/pre>\n<p>\u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u043c\u044b \u043e\u043f\u0442\u0438\u043c\u0438\u0441\u0442\u0438\u0447\u043d\u043e* \u043e\u0431\u043d\u043e\u0432\u0438\u043c ui, \u0437\u0430\u043a\u0438\u043d\u0435\u043c \u0432 \u0441\u0442\u044d\u0439\u0442 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u043d\u0430\u0448\u0435 \u043d\u043e\u0432\u043e\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435. \u041a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0441\u0440\u0430\u0437\u0443 \u0436\u0435 \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0441 \u043d\u043e\u0432\u044b\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435\u043c. \u041f\u043e\u0442\u043e\u043c \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 \u0447\u0435\u0440\u0435\u0437 \u0432\u0435\u0431\u0441\u043e\u043a\u0435\u0442, \u0437\u0430\u0442\u0435\u043c \u0440\u0435\u0441\u0435\u0442\u043d\u0438\u043c input.<\/p>\n<blockquote>\n<p>*\u041e\u043f\u0442\u0438\u043c\u0438\u0441\u0442\u0438\u0447\u043d\u043e, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0442\u0430\u043a\u043e\u0435 \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u043d\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f Optimistic update. \u041a\u043e\u0433\u0434\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0441\u043e\u0432\u0435\u0440\u0448\u0430\u0435\u0442 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u043d\u0430\u0436\u0430\u0442\u0438\u0435 \u043a\u043d\u043e\u043f\u043a\u0438 \u043b\u0430\u0439\u043a\u0430) \u0438 \u043c\u044b \u0441\u0440\u0430\u0437\u0443 \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u043c ui, \u043d\u0435 \u0434\u043e\u0436\u0438\u0434\u0430\u044f\u0441\u044c, \u043a\u043e\u0433\u0434\u0430 \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 \u044d\u0442\u043e \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0434\u043e\u0439\u0434\u0435\u0442<\/p>\n<\/blockquote>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043a\u043e\u0433\u0434\u0430 \u043c\u044b \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043e\u043d\u0438 \u0441\u0440\u0430\u0437\u0443 \u043f\u043e\u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0432 \u0447\u0430\u0442\u0435.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043e\u0442\u0432\u0435\u0442\u043d\u044b\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430. \u0418 \u0437\u0434\u0435\u0441\u044c \u0432\u0441\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043f\u0440\u043e\u0449\u0435.<\/p>\n<pre><code class=\"typescript\">onMessage: (event) =&gt;         setMessages((prevMessages) =&gt; [           ...prevMessages,           { text: event.data, type: \"server\" },         ]), <\/code><\/pre>\n<p>\u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u0441\u044f \u0432 options \u0443 \u0445\u0443\u043a\u0430 <em>useWebsocket,<\/em> \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c, \u0447\u0442\u043e \u043d\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 <em>onMessage<\/em> \u043c\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0432 \u0441\u0442\u044d\u0439\u0442 <em>messages<\/em> \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0432\u0441\u0435 \u0433\u043e\u0442\u043e\u0432\u043e!<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/47b\/e0d\/cc5\/47be0dcc5f9d36d2d8d4abeeb820d57f.png\" alt=\"Untitled\" width=\"804\" height=\"948\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/47b\/e0d\/cc5\/47be0dcc5f9d36d2d8d4abeeb820d57f.png\"\/><\/p>\n<div><figcaption>Untitled<\/figcaption><\/div>\n<\/figure>\n<p>\u0412\u0435\u0441\u044c \u043a\u043e\u0434:<\/p>\n<pre><code class=\"typescript\">import { useState } from \"react\"; import { Button } from \".\/ui\/button\"; import { Card, CardContent, CardTitle } from \".\/ui\/card\"; import { Input } from \".\/ui\/input\"; import { ScrollArea } from \".\/ui\/scroll-area\"; import { Separator } from \".\/ui\/separator\"; import { useField, useMount, useWebSocket } from \"@siberiacancode\/reactuse\";  type Message = {   text: string;   type: \"client\" | \"server\"; };  const Chat = () =&gt; {   const [messages, setMessages] = useState&lt;Message[]&gt;([]);   const messageInput = useField({ initialValue: \"\" });   const { send, status, close, open } = useWebSocket(     \"wss:\/\/echo.websocket.org\",     {       onConnected: (webSocket) =&gt; console.log(`Connected to ${webSocket.url}`),       onMessage: (event) =&gt;         setMessages((prevMessages) =&gt; [           ...prevMessages,           { text: event.data, type: \"server\" },         ]),     }   );    useMount(() =&gt; console.log(\"Connecting to websocket server...\"));   return (     &lt;Card className=\" w-80 h-96\"&gt;       &lt;CardTitle&gt;         &lt;div className=\"p-2\"&gt;Pokemon Chat&lt;\/div&gt;         &lt;Separator \/&gt;       &lt;\/CardTitle&gt;       &lt;CardContent className=\"p-0 flex flex-col\"&gt;         &lt;ScrollArea className=\" w-full h-72\"&gt;           &lt;div className=\"p-2\"&gt;             {messages.map((message, index) =&gt; {               if (message.type === \"client\")                 return (                   &lt;div className=\"flex justify-end\" key={index}&gt;                     &lt;div className=\" bg-slate-800 text-foreground rounded-md p-1.5 max-w-64 shadow-slate-800 shadow-md\"&gt;                       {message.text}                     &lt;\/div&gt;                   &lt;\/div&gt;                 );               else                 return (                   &lt;div className=\"flex\" key={index}&gt;                     &lt;div className=\" bg-slate-300 text-background rounded-md p-1.5 max-w-64 shadow-slate-300 shadow-md\"&gt;                       {message.text}                     &lt;\/div&gt;                   &lt;\/div&gt;                 );             })}           &lt;\/div&gt;         &lt;\/ScrollArea&gt;         &lt;div className=\" flex \"&gt;           &lt;Input placeholder=\"Your message...\" {...messageInput.register()} \/&gt;           &lt;Button             onClick={() =&gt; {               const message = messageInput.getValue();               setMessages((prevMessages) =&gt; [                 ...prevMessages,                 { text: message, type: \"client\" },               ]);               send(message);               messageInput.reset();             }}           &gt;             Send           &lt;\/Button&gt;         &lt;\/div&gt;       &lt;\/CardContent&gt;     &lt;\/Card&gt;   ); };  export default Chat; <\/code><\/pre>\n<h4>\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/h4>\n<p>\u041a\u0430\u043a \u043c\u044b \u0441\u043c\u043e\u0433\u043b\u0438 \u0443\u0432\u0438\u0434\u0435\u0442\u044c &#8212; \u0432\u0435\u0431\u0441\u043e\u043a\u0435\u0442\u044b \u043d\u0443\u0436\u043d\u044b \u0432 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u044f\u0445, \u043a\u043e\u0433\u0434\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0434\u043e\u043b\u0436\u043d\u044b \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442\u044c \u043c\u043e\u043c\u0435\u043d\u0442\u0430\u043b\u044c\u043d\u043e \u0438 \u043c\u043e\u043c\u0435\u043d\u0442\u0430\u043b\u044c\u043d\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0442\u044c ui, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0447\u0430\u0442\u044b \u0432 \u043c\u0435\u0441\u0441\u0435\u043d\u0434\u0436\u0435\u0440\u0430\u0445. \u041e\u0431\u044b\u0447\u043d\u044b\u0439 \u043f\u043e\u043b\u043b\u0438\u043d\u0433 \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c, \u043a\u043e\u0433\u0434\u0430 \u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u0435 \u0432\u0430\u0436\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u043d\u0430\u0441\u0442\u043e\u043b\u044c\u043a\u043e \u0431\u044b\u0441\u0442\u0440\u043e \u0438 \u0438\u0445 \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u043d\u0435 \u0441\u0442\u043e\u043b\u044c \u0432\u0430\u0436\u043d\u0430, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043f\u043e\u0447\u0442\u043e\u0432\u044b\u0435 \u0441\u0435\u0440\u0432\u0438\u0441\u044b.<\/p>\n<p>\u042d\u0442\u0430 \u0441\u0442\u0430\u0442\u044c\u044f \u043f\u043e\u043a\u0430\u0437\u0430\u043b\u0430 \u0432\u0430\u043c \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u0440\u0430\u0437\u043b\u0438\u0447\u0438\u044f \u0438 \u0441\u043f\u043e\u0441\u043e\u0431\u044b \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043f\u043e\u043b\u043b\u0438\u043d\u0433\u0430 \u0438 \u0432\u0435\u0431 \u0441\u043e\u043a\u0435\u0442\u043e\u0432. \u041b\u0443\u0447\u0448\u0435 \u0432\u0441\u0435\u0433\u043e \u0434\u043b\u044f \u044d\u0442\u0438\u0445 \u043a\u0435\u0439\u0441\u043e\u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0445\u0443\u043a\u0438 \u0438 \u0441\u0430\u043c\u0443\u044e \u043e\u0433\u0440\u043e\u043c\u043d\u0443\u044e \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u044e \u0445\u0443\u043a\u043e\u0432 \u0432 react &#8212; <a href=\"https:\/\/siberiacancode.github.io\/reactuse\/\" rel=\"noopener noreferrer nofollow\">reactuse<\/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\/833104\/\"> https:\/\/habr.com\/ru\/articles\/833104\/<\/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-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<h3>\u0412\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u0435<\/h3>\n<p>\u0412 \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 \u0432\u0435\u0431-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u0432 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u0432\u0440\u0435\u043c\u0435\u043d\u0438. \u0421\u0440\u0435\u0434\u0438 \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0451\u043d\u043d\u044b\u0445 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u0432\u044b\u0434\u0435\u043b\u044f\u044e\u0442\u0441\u044f Polling \u0438 WebSockets. \u041e\u0431\u0430 \u043f\u043e\u0434\u0445\u043e\u0434\u0430 \u0438\u043c\u0435\u044e\u0442 \u0441\u0432\u043e\u0438 \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0435 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u0438 \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f, \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442 \u0438\u0445 \u043f\u043e\u0434\u0445\u043e\u0434\u044f\u0449\u0438\u043c\u0438 \u0434\u043b\u044f \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0435\u0432. \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u0440\u0430\u0437\u043b\u0438\u0447\u0438\u044f \u043c\u0435\u0436\u0434\u0443 Polling \u0438 WebSockets, \u0438\u0445 \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430 \u0438 \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043a\u0438, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0438\u0437 \u043d\u0438\u0445 \u0432 React \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445 \u043d\u0430 \u0445\u0443\u043a\u0430\u0445.<\/p>\n<h3>Polling<\/h3>\n<p><strong>Polling<\/strong> \u2013 \u044d\u0442\u043e \u043c\u0435\u0442\u043e\u0434, \u043f\u0440\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043a\u043b\u0438\u0435\u043d\u0442 \u043f\u0435\u0440\u0438\u043e\u0434\u0438\u0447\u0435\u0441\u043a\u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445. \u042d\u0442\u043e\u0442 \u043f\u043e\u0434\u0445\u043e\u0434 \u043f\u0440\u043e\u0441\u0442 \u0432 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438, \u043d\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043d\u0435\u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u0435\u043d \u043f\u0440\u0438 \u0447\u0430\u0441\u0442\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u0445, \u0442\u0430\u043a \u043a\u0430\u043a \u043e\u043d \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0432\u0430\u0435\u0442 \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0443 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 \u0438 \u0441\u0435\u0442\u044c.<\/p>\n<figure class=\"full-width\">\n<div><figcaption>Untitled<\/figcaption><\/div>\n<\/figure>\n<p>\u0420\u0435\u0444\u0435\u0442\u0447 \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442\u044c \u043f\u0440\u0438 \u043d\u0430\u0436\u0430\u0442\u0438\u0438 \u043a\u043d\u043e\u043f\u043a\u0438, \u043f\u043e \u0438\u0441\u0442\u0435\u0447\u0435\u043d\u0438\u044e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0433\u043e \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u0432\u0440\u0435\u043c\u0435\u043d\u0438, \u0438\u043b\u0438 \u043f\u0440\u0438 \u043b\u044e\u0431\u043e\u043c \u0434\u0440\u0443\u0433\u043e\u043c \u0441\u043e\u0431\u044b\u0442\u0438\u0438.<\/p>\n<h3>WebSockets<\/h3>\n<p><strong>WebSockets<\/strong> \u2013 \u044d\u0442\u043e \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e\u0435 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u043c\u0435\u0436\u0434\u0443 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u043c \u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c. \u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u044d\u0442\u043e\u043c\u0443 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044e \u0434\u0430\u043d\u043d\u044b\u0435 \u043c\u043e\u0433\u0443\u0442 \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c\u0441\u044f \u0432 \u043e\u0431\u043e\u0438\u0445 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f\u0445 \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u0432\u0440\u0435\u043c\u0435\u043d\u0438, \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442 WebSockets \u0431\u043e\u043b\u0435\u0435 \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u044b\u043c \u0434\u043b\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u0442\u0440\u0435\u0431\u0443\u044e\u0449\u0438\u0445 \u043c\u0433\u043d\u043e\u0432\u0435\u043d\u043d\u043e\u0433\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<figure class=\"full-width\">\n<div><figcaption>Untitled<\/figcaption><\/div>\n<\/figure>\n<p>\u041a\u043b\u0438\u0435\u043d\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441, \u0430 \u0441\u0435\u0440\u0432\u0435\u0440 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0435\u043c\u0443 handshake, \u043f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442\u0441\u044f websocket \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u043c\u043e\u043c\u0435\u043d\u0442\u0430\u043b\u044c\u043d\u043e \u043f\u0440\u0438\u0445\u043e\u0434\u044f\u0442 \u043e\u0442 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0434\u043e \u0441\u0435\u0440\u0432\u0435\u0440\u0430, \u0438 \u043d\u0430\u043e\u0431\u043e\u0440\u043e\u0442.<\/p>\n<h3>\u0420\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043e\u0431\u043e\u0438\u0445 \u043f\u043e\u0434\u0445\u043e\u0434\u043e\u0432<\/h3>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c 2 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f: \u0432 \u043f\u0435\u0440\u0432\u043e\u043c \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0447\u0430\u0442 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u043f\u043e\u043b\u043b\u0438\u043d\u0433\u0430, \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e \u043a\u043d\u043e\u043f\u043a\u0443 \u201c\u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c\u201d, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442\u044c \u0440\u0435\u0444\u0435\u0442\u0447; \u0432\u043e \u0432\u0442\u043e\u0440\u043e\u043c \u0436\u0435 \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u0447\u0430\u0442 \u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c web socket \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435, \u0434\u043b\u044f \u043c\u043e\u043c\u0435\u043d\u0442\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<h3>\u0417\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438<\/h3>\n<p>\u0414\u043b\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0437\u0430\u0434\u0443\u043c\u043a\u0438 \u043c\u043d\u0435 \u043f\u0440\u0438\u0433\u043e\u0434\u0438\u0442\u0441\u044f \u0432\u0441\u0435\u0433\u043e 2 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438:<\/p>\n<ul>\n<li>\n<p><a href=\"https:\/\/ui.shadcn.com\/\" rel=\"noopener noreferrer nofollow\">shadcn\/ui<\/a> &#8212; \u0434\u043b\u044f \u043a\u0440\u0430\u0441\u0438\u0432\u044b\u0445 ui \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/siberiacancode.github.io\/reactuse\/\" rel=\"noopener noreferrer nofollow\">reactuse<\/a> &#8212; \u043b\u0443\u0447\u0448\u0430\u044f \u0443\u0442\u0438\u043b\u0438\u0442\u0430\u0440\u043d\u0430\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0441 \u043e\u0433\u0440\u043e\u043c\u043d\u044b\u043c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e\u043c \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0445 react \u0445\u0443\u043a\u043e\u0432 (\u043c\u044b \u0432\u043e\u0437\u044c\u043c\u0435\u043c \u043e\u0442\u0442\u0443\u0434\u0430 useQuery \u0438 useWebsocket)<\/p>\n<\/li>\n<\/ul>\n<p>\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0438 \u043d\u0443\u0436\u043d\u044b\u0435 \u043d\u0430\u043c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0438\u0437 ui \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 (\u044d\u0442\u043e \u043d\u0430\u0447\u0430\u043b\u043e \u0431\u0443\u0434\u0435\u0442 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u043c \u0434\u043b\u044f \u043e\u0431\u043e\u0438\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439)<\/p>\n<pre><code class=\"bash\">$yarn add @siberiacancode\/reactuse $yarn add tailwindcss $npx tailwindcss init $npx shadcn-ui@latest init $npx shadcn-ui@latest add button card input <\/code><\/pre>\n<p>\u0414\u043b\u044f \u043e\u0431\u043e\u0438\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0447\u0430\u0442\u0430. \u041d\u0430\u0447\u043d\u0435\u043c \u0441 \u043e\u0431\u044b\u0447\u043d\u043e\u0439 \u0432\u0435\u0440\u0441\u0442\u043a\u0438. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c \u0438\u0437 shadcn\/ui \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b: button, input, scroll-area, separator. (\u0441\u043c. \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044e, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043a\u0430\u043a \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b)<\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u043a\u0443 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 Chat:<\/p>\n<pre><code class=\"typescript\">import { Button } from \".\/ui\/button\"; import { Card, CardContent, CardTitle } from \".\/ui\/card\"; import { Input } from \".\/ui\/input\"; import { ScrollArea } from \".\/ui\/scroll-area\"; import { Separator } from \".\/ui\/separator\"; const Chat = () =&gt; { return ( &lt;Card className=\" w-80 h-96\"&gt; &lt;CardTitle&gt; &lt;div className=\"p-2\"&gt;Chat&lt;\/div&gt; &lt;Separator \/&gt; &lt;\/CardTitle&gt; &lt;CardContent className=\"p-0 flex flex-col\"&gt; &lt;ScrollArea className=\" w-full h-72\"&gt; &lt;div className=\" p-2\"&gt; &lt;div className=\"flex\"&gt; &lt;div className=\" bg-slate-300 text-background rounded-md p-1.5 max-w-64 shadow-slate-300 shadow-md\"&gt; Message to you &lt;\/div&gt; &lt;\/div&gt; &lt;div className=\"flex justify-end\"&gt; &lt;div className=\" bg-slate-800 text-foreground rounded-md p-1.5 max-w-64 shadow-slate-800 shadow-md\"&gt; Message from you &lt;\/div&gt; &lt;\/div&gt; &lt;\/div&gt; &lt;\/ScrollArea&gt; &lt;div className=\" flex \"&gt; &lt;Input placeholder=\"Your message...\" className=\"\" \/&gt; &lt;Button className=\"\"&gt;Send&lt;\/Button&gt; &lt;\/div&gt; &lt;\/CardContent&gt; &lt;\/Card&gt; ); }; export default Chat; <\/code><\/pre>\n<p>\u041f\u043e\u043b\u0443\u0447\u0438\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 ui:<\/p>\n<figure class=\"full-width\">\n<div><figcaption>Untitled<\/figcaption><\/div>\n<\/figure>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u043c type Message:<\/p>\n<pre><code class=\"typescript\">type Message = {   text: string;   type: \"client\" | \"server\"; }; <\/code><\/pre>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 <em>messages,<\/em> \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0431\u0443\u0434\u0435\u043c \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432\u0441\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f:<\/p>\n<pre><code class=\"typescript\">import { useState } from \"react\"; <\/code><\/pre>\n<pre><code class=\"typescript\">const messages = useState&lt;Message[]&gt;([]) <\/code><\/pre>\n<p>\u041d\u0435\u043c\u043d\u043e\u0433\u043e \u043f\u043e\u043c\u0435\u043d\u044f\u0435\u043c \u0432\u0435\u0440\u0441\u0442\u043a\u0443, \u0447\u0442\u043e\u0431\u044b \u0432 \u0447\u0430\u0442\u0435 \u043e\u0442\u043e\u0431\u0440\u043e\u0436\u0430\u043b\u0438\u0441\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0438\u0437 \u0441\u0442\u044d\u0439\u0442\u0430 messages \u0438 \u043d\u0430 \u043d\u0438\u0445 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u043b\u0438\u0441\u044c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0435 \u0441\u0442\u0438\u043b\u0438, \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0438 \u0441 \u0442\u0435\u043c, \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043b\u0438 \u0442\u0438\u043f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u201cserver\u201d \u0438\u043b\u0438 \u201cclient\u201d<\/p>\n<pre><code class=\"typescript\">&lt;ScrollArea className=\" w-full h-72\"&gt;   &lt;div className=\"p-2\"&gt;     {messages.map((message, index) =&gt; {       if (message.type === \"client\")         return (           &lt;div className=\"flex justify-end\" key={index}&gt;             &lt;div className=\" bg-slate-800 text-foreground rounded-md p-1.5 max-w-64 shadow-slate-800 shadow-md\"&gt;               {message.text}             &lt;\/div&gt;           &lt;\/div&gt;         );       else         return (           &lt;div className=\"flex\"&gt;             &lt;div className=\" bg-slate-300 text-background rounded-md p-1.5 max-w-64 shadow-slate-300 shadow-md\"&gt;               {message.text}             &lt;\/div&gt;           &lt;\/div&gt;         );     })}   &lt;\/div&gt; &lt;\/ScrollArea&gt;; <\/code><\/pre>\n<h4>\u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0445\u0443\u043a \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043f\u043e\u043b\u044f\u043c\u0438 \u0432\u0432\u043e\u0434\u0430<\/h4>\n<p><strong>useField &#8212;<\/strong> \u044d\u0442\u043e\u0442 \u0445\u0443\u043a \u0438\u0437 \u043f\u0430\u043a\u0435\u0442\u0430 <em>reactuse<\/em> \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u043d\u043e\u0433\u043e \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0441\u0442\u0432\u0438\u044f \u0441 \u043f\u043e\u043b\u044f\u043c\u0438 \u0432\u0432\u043e\u0434\u0430.<\/p>\n<pre><code class=\"typescript\">const messageInput = useField({initialValue: ''}) <\/code><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u043c\u044b \u0437\u0430\u0434\u0430\u043b\u0438 initialValue, \u0440\u0430\u0432\u043d\u043e\u0435 \u043f\u0443\u0441\u0442\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0435. \u0414\u0430\u043b\u0435\u0435 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u043a messageInput, \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u043f\u043e\u043b\u0435\u043c \u0432\u0432\u043e\u0434\u0430.<\/p>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u043c \u043a \u043d\u0430\u0448\u0435\u043c\u0443 \u0438\u043d\u043f\u0443\u0442\u0443 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435:<\/p>\n<pre><code class=\"typescript\">&lt;Input placeholder=\"Your message...\" {...messageInput.register()} \/&gt; <\/code><\/pre>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043c\u044b \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u043c \u0438 \u043f\u0440\u0438\u0432\u044f\u0437\u044b\u0432\u0430\u0435\u043c \u0445\u0443\u043a \u043a \u044d\u0442\u043e\u043c\u0443 \u043f\u043e\u043b\u044e \u0432\u0432\u043e\u0434\u0430<\/p>\n<h4>1 &#8212; \u041c\u0435\u0442\u043e\u0434 Polling<\/h4>\n<p>\u0414\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0438\u0437 \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u0432 \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u044c\u0441\u044f \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0441\u0432\u043e\u0439 \u043c\u043e\u043a\u043e\u0432\u044b\u0439 \u0441\u0435\u0440\u0432\u0435\u0440. \u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u0441 polling \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0441\u044c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u043e\u0439 \u043e\u0442 \u0441\u043e\u0437\u0434\u0430\u0442\u0438\u043b\u044f reactuse &#8212; <a href=\"https:\/\/www.npmjs.com\/package\/mock-config-server\" rel=\"noopener noreferrer nofollow\"><strong>? Mock Config Server<\/strong><\/a><\/p>\n<p>\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c \u043f\u0430\u043a\u0435\u0442:<\/p>\n<pre><code class=\"bash\">$yarn add mock-config-server --dev <\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u0434\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e \u043f\u0430\u043a\u0435\u0442\u0430. \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0444\u0430\u0439\u043b <em>mock-server.config.js:<\/em><\/p>\n<pre><code class=\"javascript\">\/** @type {import('mock-config-server').MockServerConfig} *\/  let messages = [];  const mockServerConfig = {   rest: {     baseUrl: \"\/api\",     configs: [       {         path: \"\/messages\",         method: \"get\",         routes: [{ data: messages }],       },       {         path: \"\/messages\/new\",         method: \"post\",         routes: [{ data: { success: \"true\" } }],         interceptors: {           response: (data, { request }) =&gt; {             messages.push({               text: request.body.text,               type: \"client\",             });             messages.push({               text: request.body.text,               type: \"server\",             });              return data;           },         },       },     ],   }, };  export default mockServerConfig; <\/code><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e <em>messages<\/em>. \u0412 \u043d\u0435\u0439 \u0431\u0443\u0434\u0435\u043c \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432\u0441\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f. \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043c\u0430\u0440\u0448\u0440\u0443\u0442 \/messages \u0438 \u0437\u0430\u043f\u0440\u043e\u0441 GET. \u042d\u0442\u043e\u0442 \u0437\u0430\u043f\u0440\u043e\u0441 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0441\u0442\u043e \u043e\u0442\u0434\u0430\u0432\u0430\u0442\u044c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e messages, \u0440\u0430\u0432\u043d\u0443\u044e \u0432\u0441\u0435\u043c \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u043c \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u044b\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f\u043c \u0432 \u043c\u0430\u0441\u0441\u0438\u0432\u0435. \u0414\u0430\u043b\u0435\u0435 POST \u0437\u0430\u043f\u0440\u043e\u0441 \/messages\/new. \u0427\u0435\u0440\u0435\u0437 <em>interceptors<\/em> \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u043a\u043e\u0433\u0434\u0430 \u043f\u0440\u0438\u0434\u0435\u0442 \u044d\u0442\u043e\u0442 \u0437\u0430\u043f\u0440\u043e\u0441. \u0412 \u044d\u0442\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043c\u044b \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u043c \u0442\u0435\u043a\u0441\u0442 \u0438\u0437 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0432 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e <em>messages<\/em> 2 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0441 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u043c \u0442\u0435\u043a\u0441\u0442\u043e\u043c: \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0438 \u043e\u0442 \u043a\u043b\u0438\u0435\u043d\u0442\u0430.<\/p>\n<p>\u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u043c\u043e\u043a\u043e\u0432\u043e\u0433\u043e \u044d\u0445\u043e-\u0447\u0430\u0442 \u0430\u043f\u0438 \u0433\u043e\u0442\u043e\u0432\u0430! \u0417\u0430\u043f\u0443\u0441\u0442\u0438\u043c \u0441\u0435\u0440\u0432\u0435\u0440:<\/p>\n<pre><code class=\"bash\"> npx mock-config-server <\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0432\u0441\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u043f\u043e <a href=\"http:\/\/localhost:31299\" rel=\"noopener noreferrer nofollow\">http:\/\/localhost:31299<\/a>\/api<\/p>\n<p>\u0412\u0435\u0440\u043d\u0435\u043c\u0441\u044f \u043a \u0431\u0430\u0437\u043e\u0432\u043e\u0439 \u0432\u0435\u0440\u0441\u0442\u043a\u0435:<\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0437\u0430\u043f\u0440\u043e\u0441 \u0437\u0430 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0445\u0443\u043a\u0430 useQuery:<\/p>\n<pre><code class=\"typescript\">import { useField, useQuery, useMutation } from \"@siberiacancode\/reactuse\"; <\/code><\/pre>\n<pre><code class=\"typescript\">const { data, refetch, isRefetching, isLoading, isError, error } = useQuery(   () =&gt; fetch(\"&lt;http:\/\/localhost:31299\/api\/messages&gt;\").then((res) =&gt; res.json()),   {     refetchInterval: 1200000,     keys: [\"messages\"],     onSuccess: (data) =&gt; setMessages(data),   } ); <\/code><\/pre>\n<p>\u0412 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c callback \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0438 \u043e\u0431\u044a\u0435\u043a\u0442 options. \u0412 \u043d\u0435\u043c \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u043a\u043b\u044e\u0447,  <em>refetchInterval,<\/em> \u0447\u0442\u043e\u0431\u044b \u0437\u0430\u043f\u0440\u043e\u0441 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u043b\u0441\u044f \u0437\u0430\u043d\u043e\u0432\u043e \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0447\u0435\u0440\u0435\u0437 120000 \u043c\u0438\u043b\u0438\u0441\u0435\u043a\u0443\u043d\u0434 (20 \u043c\u0438\u043d\u0443\u0442) \u0438 <em>onSuccess &#8212;<\/em> \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0443\u0441\u043f\u0435\u0445\u0430 **\u043f\u0440\u0438\u0441\u0432\u043e\u0438\u043c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 (data) \u0441\u0442\u044d\u0439\u0442\u0443 <em>messages<\/em>. \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0440\u044f\u0434 \u0441\u0442\u044d\u0439\u0442\u043e\u0432 \u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u044b \u0437\u0430\u044e\u0437\u0430\u0435\u043c \u043f\u043e\u0437\u0436\u0435.<\/p>\n<p>\u041d\u0435\u043c\u043d\u043e\u0433\u043e \u043f\u043e\u043c\u0435\u043d\u044f\u0435\u043c \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u043a\u0443 \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u0430 \u043a\u0430\u0440\u0442\u043e\u0447\u043a\u0438:<\/p>\n<pre><code class=\"typescript\">&lt;ScrollArea className=\" w-full h-72\"&gt;   &lt;div className=\"p-2\"&gt;     {isLoading || isRefetching ? (       &lt;p className=\"text-center\"&gt;Wait...&lt;\/p&gt;     ) : isError ? (       &lt;p className=\"text-center\"&gt;Error {error?.message}&lt;\/p&gt;     ) : (       messages.map((message, index) =&gt; {         if (message.type === \"client\")           return (             &lt;div className=\"flex justify-end\" key={index}&gt;               &lt;div className=\" bg-slate-800 text-foreground rounded-md p-1.5 max-w-64 shadow-slate-800 shadow-md\"&gt;                 {message.text}               &lt;\/div&gt;             &lt;\/div&gt;           );         else           return (             &lt;div className=\"flex\" key={index}&gt;               &lt;div className=\" bg-slate-300 text-background rounded-md p-1.5 max-w-64 shadow-slate-300 shadow-md\"&gt;                 {message.text}               &lt;\/div&gt;             &lt;\/div&gt;           );       })     )}   &lt;\/div&gt; &lt;\/ScrollArea&gt;; <\/code><\/pre>\n<p>\u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u0448\u0438\u0431\u043a\u0438 \u043e\u0442\u043e\u0431\u0440\u0430\u0437\u0438\u043c \u043e\u0448\u0438\u0431\u043a\u0443, \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0438\u043b\u0438 \u0440\u0435\u0444\u0435\u0442\u0447\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u043c Wait\u2026 \u0418\u043d\u0430\u0447\u0435 &#8212; \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u043c ui<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0437\u0430\u0439\u043c\u0435\u043c\u0441\u044f \u0440\u0435\u0444\u0435\u0442\u0447\u0435\u043c \u043f\u043e \u043a\u043d\u043e\u043f\u043a\u0435. \u041f\u0440\u043e\u0441\u0442\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043a \u043a\u043d\u043e\u043f\u043a\u0435 Refetch \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435:<\/p>\n<pre><code class=\"typescript\">&lt;Button onClick={()=&gt;refetch()}&gt;Refetch&lt;\/Button&gt; <\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0440\u0438 \u043d\u0430\u0436\u0430\u0442\u0438\u0438 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442\u044c \u0440\u0435\u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0431\u0443\u0434\u0435\u043c \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f.<\/p>\n<pre><code class=\"typescript\">const { mutateAsync } = useMutation(async (text) =&gt; {     await fetch(\"&lt;http:\/\/localhost:31299\/api\/messages\/new&gt;\", {       method: \"POST\",       body: JSON.stringify({ text: text }),       headers: {         Accept: \"application\/json\",         \"Content-Type\": \"application\/json\",       },     });   }); <\/code><\/pre>\n<p>\u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e <em>mutateAsync<\/em> \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u044f \u0445\u0443\u043a <em>useMutation<\/em>.  \u0412 callback \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c POST \u0437\u0430\u043f\u0440\u043e\u0441 \u0441 body \u0438 \u0437\u0430\u0433\u0430\u043b\u043e\u0432\u043a\u0430\u043c\u0438.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0432\u044b\u0437\u0432\u0430\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e <em>mutateAsync<\/em> \u0447\u0442\u043e\u0431\u044b \u0441\u043e\u0432\u0435\u0440\u0448\u0438\u0442\u044c \u043c\u0443\u0442\u0430\u0446\u0438\u044e \u0434\u0430\u043d\u043d\u044b\u0445 (\u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435). \u0412\u044b\u0437\u044b\u0432\u0435\u043c \u0435\u0435 \u043a\u0430\u043a \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043d\u0430\u0436\u043c\u0435\u0442 Send. \u041f\u043e\u0441\u043b\u0435 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0440\u0435\u0441\u0435\u0442\u043d\u0435\u043c \u0444\u043e\u0440\u043c\u0443<\/p>\n<pre><code class=\"typescript\">&lt;Button   onClick={async () =&gt; {     await mutateAsync(messageInput.getValue());     messageInput.reset();   }} &gt;   Send &lt;\/Button&gt;; <\/code><\/pre>\n<p>\u0413\u043e\u0442\u043e\u0432\u043e!<\/p>\n<figure class=\"full-width\">\n<div><figcaption>Untitled<\/figcaption><\/div>\n<\/figure>\n<p>\u0412\u0435\u0441\u044c \u043a\u043e\u0434:<\/p>\n<pre><code class=\"typescript\">import { useState } from \"react\"; import { Button } from \".\/ui\/button\"; import { Card, CardContent, CardTitle } from \".\/ui\/card\"; import { Input } from \".\/ui\/input\"; import { ScrollArea } from \".\/ui\/scroll-area\"; import { Separator } from \".\/ui\/separator\"; import { useField, useQuery, useMutation } from \"@siberiacancode\/reactuse\";  type Message = {   text: string;   type: \"client\" | \"server\"; };  const Chat = () =&gt; {   const<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\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-428020","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/428020","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=428020"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/428020\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=428020"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=428020"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=428020"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}