{"id":358569,"date":"2024-05-21T00:14:40","date_gmt":"2024-05-21T00:14:40","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=358569"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=358569","title":{"rendered":"<span>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0434\u043b\u044f real-time \u043e\u0431\u043c\u0435\u043d\u0430 \u0433\u0435\u043e\u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u0441 React, Socket.io \u0438 Leaflet<\/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<p>\u0415\u0441\u0442\u044c \u043c\u043d\u043e\u0433\u043e \u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043d\u0430 React \u0438 Socket.io. \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0442\u0430\u043a\u0438\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u043f\u043e\u043b\u0435\u0437\u043d\u043e \u0434\u043b\u044f \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f, \u043d\u043e \u043c\u043d\u0435 \u0437\u0430\u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0447\u0435\u0433\u043e-\u0442\u043e \u0431\u043e\u043b\u0435\u0435 \u0442\u0432\u043e\u0440\u0447\u0435\u0441\u043a\u043e\u0433\u043e. \u041f\u0440\u0438\u0448\u043b\u0430 \u0438\u0434\u0435\u044f \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u0433\u0434\u0435 \u043c\u043e\u0436\u043d\u043e \u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c.<\/p>\n<p>\u0418\u0442\u0430\u043a, \u043d\u0430\u0447\u043d\u0435\u043c.<\/p>\n<details class=\"spoiler\">\n<summary>\u041d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u043a\u0440\u0438\u043d\u043e\u0432 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c, \u0438 GitHub<\/summary>\n<div class=\"spoiler__content\">\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/145\/8b7\/c50\/1458b7c500bb2b62bd47ee4d2d91e7ef.png\" width=\"1378\" height=\"750\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/145\/8b7\/c50\/1458b7c500bb2b62bd47ee4d2d91e7ef.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/e14\/8af\/579\/e148af579fa15cf8072357f711949704.png\" width=\"800\" height=\"450\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/e14\/8af\/579\/e148af579fa15cf8072357f711949704.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/bf1\/ecc\/f33\/bf1eccf333457da4a694e274d1c30169.png\" width=\"800\" height=\"450\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/bf1\/ecc\/f33\/bf1eccf333457da4a694e274d1c30169.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/32b\/6e7\/b3c\/32b6e7b3c9f13448ed305c6196fc3eb1.png\" width=\"800\" height=\"198\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/32b\/6e7\/b3c\/32b6e7b3c9f13448ed305c6196fc3eb1.png\"\/><\/figure>\n<p>\u041c\u043e\u0436\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f, \u043a\u043e\u0433\u0434\u0430 \u043a\u0442\u043e-\u0442\u043e \u043f\u0440\u0438\u0441\u043e\u0435\u0434\u0438\u043d\u044f\u0435\u0442\u0441\u044f \u0438\u043b\u0438 \u0443\u0445\u043e\u0434\u0438\u0442 \u0438\u0437 \u043a\u0430\u043d\u0430\u043b\u0430, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0432\u0438\u0434\u0435\u0442\u044c \u0442\u0435\u043a\u0443\u0449\u0435\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439, \u043d\u0430\u0445\u043e\u0434\u044f\u0449\u0438\u0445\u0441\u044f \u0432 \u0441\u0435\u0442\u0438.<\/p>\n<p>\u041a\u0430\u043a \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0443\u043d\u0435\u0440 \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u0435\u0442 \u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f \u0441\u0432\u043e\u0438\u043c \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c, \u043a\u0430\u043d\u0430\u043b \u0443\u0434\u0430\u043b\u044f\u0435\u0442\u0441\u044f, \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 \u043d\u0435 \u043c\u043e\u0433\u0443\u0442 \u0432\u0438\u0434\u0435\u0442\u044c \u043b\u043e\u043a\u0430\u0446\u0438\u044e.<\/p>\n<p>\u0422\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043c\u043e\u0436\u043d\u043e \u043d\u0435 \u0432\u044b\u0445\u043e\u0434\u044f \u043d\u0430 \u0443\u043b\u0438\u0446\u0443 (\u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f).<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/dcf\/9e7\/c24\/dcf9e7c2441b2dd3c0d74e922baac8bc.png\" width=\"800\" height=\"697\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/dcf\/9e7\/c24\/dcf9e7c2441b2dd3c0d74e922baac8bc.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/31f\/231\/d83\/31f231d83e5a7b61d37a63cd62b815a9.png\" width=\"761\" height=\"468\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/31f\/231\/d83\/31f231d83e5a7b61d37a63cd62b815a9.png\"\/><\/figure>\n<p>GitHub: <a href=\"https:\/\/github.com\/manish-mehra\/locshare\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/manish-mehra\/locshare<\/a><\/p>\n<\/div>\n<\/details>\n<h2>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/h2>\n<p>\u041d\u0430 \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434\u0435 \u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u043b React-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c Vite, TypeScript \u0438 Tailwind CSS. \u0414\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442 \u043d\u0430 \u043a\u0430\u0440\u0442\u0435 \u044f \u0432\u0437\u044f\u043b \u0438\u0437\u0432\u0435\u0441\u0442\u043d\u0443\u044e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 \u0441 \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u043c \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u043c \u043a\u043e\u0434\u043e\u043c \u043f\u043e\u0434 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c Leaflet.<\/p>\n<p>\u042f \u043d\u0435\u0434\u0430\u0432\u043d\u043e \u043d\u0430\u0447\u0430\u043b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c TypeScript \u0438 \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u043b \u0435\u0433\u043e \u0432 \u044d\u0442\u043e\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435. \u041e\u0434\u043d\u0430\u043a\u043e \u0432\u0430\u0436\u043d\u043e \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e TypeScript \u043d\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u043c \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u043c.<\/p>\n<p>\u0412\u043e\u0442 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434\u0430:<\/p>\n<pre><code class=\"javascript\">{   \"name\": \"client\",   \"private\": true,   \"version\": \"0.0.0\",   \"type\": \"module\",   \"scripts\": {     \"dev\": \"vite\",     \"build\": \"tsc &amp;&amp; vite build\",     \"lint\": \"eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0\",     \"preview\": \"vite preview\"   },   \"dependencies\": {     \"@types\/leaflet\": \"^1.9.6\",     \"@types\/react-leaflet\": \"^3.0.0\",     \"react\": \"^18.2.0\",     \"react-dom\": \"^18.2.0\",     \"react-icons\": \"^4.11.0\",     \"react-leaflet\": \"^4.2.1\",     \"react-router-dom\": \"^6.16.0\",     \"react-toastify\": \"^9.1.3\",     \"socket.io-client\": \"^4.7.2\"   },   \"devDependencies\": {     \"@types\/react\": \"^18.2.15\",     \"@types\/react-dom\": \"^18.2.7\",     \"@typescript-eslint\/eslint-plugin\": \"^6.0.0\",     \"@typescript-eslint\/parser\": \"^6.0.0\",     \"@vitejs\/plugin-react\": \"^4.0.3\",     \"autoprefixer\": \"^10.4.15\",     \"eslint\": \"^8.45.0\",     \"eslint-plugin-react-hooks\": \"^4.6.0\",     \"eslint-plugin-react-refresh\": \"^0.4.3\",     \"postcss\": \"^8.4.29\",     \"tailwindcss\": \"^3.3.3\",     \"typescript\": \"^5.0.2\",     \"vite\": \"^4.4.5\"   } }<\/code><\/pre>\n<p>\u0414\u043b\u044f \u0431\u044d\u043a\u0435\u043d\u0434\u0430 \u0435\u0441\u0442\u044c \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u0441\u0435\u0440\u0432\u0435\u0440 node-express \u0441\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c\u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044f\u043c\u0438:<\/p>\n<pre><code class=\"javascript\">{   \"name\": \"server\",   \"version\": \"1.0.0\",   \"description\": \"\",   \"main\": \"index.js\",   \"scripts\": {     \"test\": \"echo \\\"Error: no test specified\\\" &amp;&amp; exit 1\",     \"build\": \"tsc\",     \"start\": \"node dist\/index.js\",     \"dev\": \"concurrently \\\"npx tsc --watch\\\" \\\"nodemon -q dist\/index.js\\\"\"   },   \"keywords\": [],   \"author\": \"\",   \"license\": \"ISC\",   \"dependencies\": {     \"cors\": \"^2.8.5\",     \"dotenv\": \"^16.3.1\",     \"express\": \"^4.18.2\",     \"socket.io\": \"^4.7.2\"   },   \"devDependencies\": {     \"@types\/express\": \"^4.17.17\",     \"concurrently\": \"^8.2.0\",     \"nodemon\": \"^3.0.1\",     \"typescript\": \"^5.2.2\"   } }<\/code><\/pre>\n<h2>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0430\u043f\u043e\u043a <\/h2>\n<p>React:<\/p>\n<pre><code class=\"javascript\">? src \u251c\u2500\u2500 ? components \u2502   \u251c\u2500\u2500 ? Element \u2502   \u2502   \u251c\u2500\u2500 ? Header \u2502   \u2502   \u251c\u2500\u2500 ? Map \u2502   \u2502   \u251c\u2500\u2500 ? Status \u2502   \u2502   \u251c\u2500\u2500 ? StatusPanel \u2502   \u251c\u2500\u2500 ? Layout \u251c\u2500\u2500 ? context \u2502   \u251c\u2500\u2500 ? socket.tsx \u251c\u2500\u2500 ? pages \u2502   \u251c\u2500\u2500 ? Home.tsx \u2502   \u251c\u2500\u2500 ? Location.tsx \u251c\u2500\u2500 ? types \u251c\u2500\u2500 ? App.tsx \u251c\u2500\u2500 ? main.tsx \u251c\u2500\u2500 ? index.css ...rest<\/code><\/pre>\n<p>Node:<\/p>\n<pre><code class=\"javascript\">? src \u251c\u2500\u2500 ? index.ts<\/code><\/pre>\n<h2>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 Socket Context<\/h2>\n<p>\u0421\u043e\u0445\u0440\u0430\u043d\u044f\u044f \u0441\u043e\u043a\u0435\u0442 \u0432 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435, \u0435\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u043c \u0434\u043b\u044f \u0432\u0441\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0424\u0443\u043d\u043a\u0446\u0438\u044f connectSocket \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435. \u0415\u0441\u043b\u0438 \u0441\u043e\u043a\u0435\u0442 &#8212; null (\u043d\u0435\u0442 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0433\u043e \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f), \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u043d\u043e\u0432\u043e\u0435 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0441\u043e\u043a\u0435\u0442\u0430. \u0415\u0441\u043b\u0438 \u0441\u043e\u043a\u0435\u0442 &#8212; \u043d\u0435 null (\u043e\u0442\u043a\u043b\u044e\u0447\u0435\u043d), \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u043a \u0441\u043e\u043a\u0435\u0442\u0443.<\/p>\n<pre><code class=\"javascript\">\/\/ SocketProvider.js import {useState, createContext, useContext, JSX} from 'react' import {io, Socket} from 'socket.io-client' import { SOCKET_URL } from '..\/config'  type SocketContextType = {   socket: Socket | null;   connectSocket: () => void; }  type SocketProviderProps = {   children: JSX.Element }  export const SocketContext = createContext&lt;SocketContextType | null>(null)  export const SocketProvider = ({children}: SocketProviderProps) => {   const [socket, setSocket] = useState&lt;Socket | null>(null)    const connectSocket = () => {     if(!socket) {       const newSocket: Socket = io(SOCKET_URL)       setSocket(newSocket)       return     }     socket.connect()   }    return (     &lt;SocketContext.Provider value={{socket, connectSocket}}>       {children}     &lt;\/SocketContext.Provider>   ) }  export const useSocket = () => {   const context = useContext(SocketContext)   if(!context) {     throw new Error('Something went wrong!')   }   return context }<\/code><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u0431\u044b\u043b\u0438 \u0441\u0434\u0435\u043b\u0430\u043d\u044b \u0443\u043f\u0440\u043e\u0449\u0435\u043d\u0438\u044f. \u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0439 \u0445\u0443\u043a useSocket, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u043b\u043e\u0433\u0438\u043a\u0443 \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a SocketContext \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 SocketProvider. \u0422\u0430\u043a\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u0443\u043f\u0440\u043e\u0449\u0430\u0435\u0442 \u043a\u043e\u0434, \u0434\u0435\u043b\u0430\u044f \u0435\u0433\u043e \u0431\u043e\u043b\u0435\u0435 \u0447\u0438\u0442\u0430\u0435\u043c\u044b\u043c \u0438 \u043f\u043e\u043d\u044f\u0442\u043d\u044b\u043c \u043f\u0440\u0438 \u0440\u0430\u0431\u043e\u0442\u0435 \u0441\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u043c\u0438 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430  \u0432 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430\u0445.<\/p>\n<h2>\u041e\u0431\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043e\u043c \u0441\u043e\u043a\u0435\u0442\u0430<\/h2>\n<pre><code class=\"javascript\">import React from 'react' import ReactDOM from 'react-dom\/client' import App from '.\/App.tsx' import '.\/index.css' import { SocketProvider } from '.\/context\/socket.tsx' import {ToastContainer} from 'react-toastify'  ReactDOM.createRoot(document.getElementById('root')!).render(   &lt;React.StrictMode>     &lt;SocketProvider>       &lt;>         &lt;App \/>         &lt;ToastContainer newestOnTop\/>       &lt;\/>     &lt;\/SocketProvider>   &lt;\/React.StrictMode>, )<\/code><\/pre>\n<h2>\u0420\u043e\u0443\u0442\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f<\/h2>\n<p>\u0417\u0434\u0435\u0441\u044c \u0435\u0441\u0442\u044c \u0434\u0432\u0435 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b: home \u0438 location. \u0412 home \u043c\u043e\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043a\u0430\u043d\u0430\u043b \u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435. \u0421\u0442\u0440\u0430\u043d\u0438\u0446\u0430 location \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u0442\u0441\u044f, \u043a\u043e\u0433\u0434\u0430 URL \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0448\u0430\u0431\u043b\u043e\u043d\u0443 \/location\/1242, \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u044f, \u0447\u0442\u043e 1242 &#8212; \u044d\u0442\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0439 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u043a\u0430\u043d\u0430\u043b\u0430 \u0438\u043b\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440.<\/p>\n<p>\u042d\u0442\u0438 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u043e\u0431\u0435\u0440\u043d\u0443\u0442\u044b \u0432 Layout Component.<\/p>\n<pre><code class=\"javascript\">import { BrowserRouter, Routes, Route } from 'react-router-dom' import Layout from '.\/components\/Layout' import Home from '.\/pages\/Home' import Location from '.\/pages\/Location'  function App() {    return (     &lt;BrowserRouter>       &lt;Routes>         &lt;Route path=\"\/\" element={&lt;Layout \/>}>           &lt;Route index element={&lt;Home \/>} \/>           &lt;Route path=\"location\/:roomId\" element={&lt;Location \/>}\/>         &lt;\/Route>       &lt;\/Routes>     &lt;\/BrowserRouter>   ) }  export default App<\/code><\/pre>\n<p>Layout Component<\/p>\n<pre><code class=\"javascript\">import { Outlet } from 'react-router-dom' import Header from '..\/Elements\/Header'  function index() {   return (     &lt;div className='flex justify-center px-3 py-2'>       &lt;div className='flex flex-col w-full md:min-w-full xl:min-w-[1100px] xl:max-w-[1200px] mb-4'>         &lt;Header \/>         &lt;main>           &lt;Outlet \/>         &lt;\/main>       &lt;\/div>     &lt;\/div>   ) }  export default index<\/code><\/pre>\n<h2>\u0414\u043e\u0441\u0442\u0443\u043f \u043a \u043b\u043e\u043a\u0430\u0446\u0438\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f<\/h2>\n<p>\u0414\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0433\u0435\u043e\u043b\u043e\u043a\u0430\u0446\u0438\u0438, \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c\u044b\u0439 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u043c. \u042d\u0442\u043e \u0432\u044b\u0437\u043e\u0432\u0435\u0442 \u0432\u0441\u043f\u043b\u044b\u0432\u0430\u044e\u0449\u0435\u0435 \u043e\u043a\u043d\u043e, \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u044e\u0449\u0435\u0435 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043d\u0430 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044e.<\/p>\n<pre><code class=\"javascript\">\/\/ \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0442\u0435\u043a\u0443\u0449\u0443\u044e \u043b\u043e\u043a\u0430\u0446\u0438\u044e navigator.geolocation.getCurrentPosition(success, error, options)<\/code><\/pre>\n<p>success, error (\u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e), options (\u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e) \u2014 \u044d\u0442\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0435\u043c\u044b\u0435 \u043a\u043e\u043b\u043b\u0431\u044d\u043a-\u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u0438 \u0447\u0435\u0440\u0435\u0437 \u043d\u0438\u0445 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u0430\u043c \u0438\u043b\u0438 \u043e\u0448\u0438\u0431\u043a\u0435 \u0438\u043b\u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b. \u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 \u0432 <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/Geolocation\/getCurrentPosition\" rel=\"noopener noreferrer nofollow\">\u0434\u043e\u043a\u0435 Mozilla<\/a>.<\/p>\n<p>\u041f\u0440\u043e\u0441\u0442\u043e \u0442\u0435\u043a\u0443\u0449\u0430\u044f \u043f\u043e\u0437\u0438\u0446\u0438\u044f \u043d\u0435 \u043d\u0443\u0436\u043d\u0430. \u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0438\u043c\u0435\u043d\u043d\u043e \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0442\u044c \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438\u0437 \u0442\u043e\u0447\u043a\u0438 \u0410 \u0432 \u0442\u043e\u0447\u043a\u0443 \u0411.<\/p>\n<p>\u041c\u044b \u043c\u043e\u0433\u043b\u0438 \u0431\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e setInterval, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043d\u0435\u043e\u0434\u043d\u043e\u043a\u0440\u0430\u0442\u043d\u043e \u0431\u044b \u0432\u044b\u0437\u044b\u0432\u0430\u043b\u0430 getCurrentPosition(). \u041d\u043e \u043e\u043d\u0430 \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0433\u0435\u043e\u043b\u043e\u043a\u0430\u0446\u0438\u0438 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0434\u0440\u0443\u0433\u043e\u0439 \u043c\u0435\u0442\u043e\u0434, watchPosition(). \u0418 \u044d\u0442\u043e\u0442 \u043c\u0435\u0442\u043e\u0434 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437, \u043a\u043e\u0433\u0434\u0430 \u043f\u043e\u0437\u0438\u0446\u0438\u044f \u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f.<\/p>\n<pre><code class=\"javascript\">\/\/ \u0443\u0437\u043d\u0430\u0442\u044c \u0442\u0435\u043a\u0443\u0449\u0443\u044e \u043b\u043e\u043a\u0430\u0446\u0438\u044e let id = navigator.geolocation.watchPosition(success, error, options)  \/\/ \u043e\u0447\u0438\u0441\u0442\u043a\u0430 navigator.geolocation.clearWatch(id)<\/code><\/pre>\n<p>\u041c\u0435\u0442\u043e\u0434 watchPosition \u043f\u043e\u0445\u043e\u0436 \u043d\u0430 setTimeout \u0438\u043b\u0438 setInterval, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e \u0432 \u0444\u043e\u043d\u043e\u0432\u043e\u043c \u0440\u0435\u0436\u0438\u043c\u0435 \u0438 \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0435\u0442 \u0442\u0435\u043a\u0443\u0449\u0443\u044e \u043f\u043e\u0437\u0438\u0446\u0438\u044e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. \u0421\u043e\u0445\u0440\u0430\u043d\u044f\u044f \u0435\u0433\u043e \u0432 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439, \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442\u0441\u044f \u0438 \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043d\u0435\u0433\u043e. \u041f\u043e\u0437\u0436\u0435, \u043a\u043e\u0433\u0434\u0430 \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0442\u044c \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f, \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043e\u0447\u0438\u0441\u0442\u0438\u0442\u044c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e \u0438\u043b\u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0435\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043a\u0430\u043a null. \u0415\u0441\u043b\u0438 \u044d\u0442\u043e\u0433\u043e \u043d\u0435 \u0441\u0434\u0435\u043b\u0430\u0442\u044c, \u0432\u0441\u0435 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0432 \u0444\u043e\u043d\u043e\u0432\u043e\u043c \u0440\u0435\u0436\u0438\u043c\u0435, \u0447\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0438\u0432\u0435\u0441\u0442\u0438 \u043a \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430\u043c \u0441 \u043f\u0430\u043c\u044f\u0442\u044c\u044e \u0438 \u043d\u0435\u043d\u0443\u0436\u043d\u043e\u043c\u0443 \u043f\u043e\u0442\u0440\u0435\u0431\u043b\u0435\u043d\u0438\u044e \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432.<\/p>\n<pre><code class=\"javascript\">type GeolocationPosition = {   lat: number   lng: number } type LocationStatus = 'accessed' | 'denied' | 'unknown' | 'error'  export default function Home() {   const [locationStatus, setLocationStatus] = useState&lt;LocationStatus>('unknown')   const [position, setPosition] = useState&lt;GeolocationPosition | null>(null)    useEffect(() => {     let watchId: number | null = null         \/\/ \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0432\u043e\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0442\u044c \u0433\u0435\u043e\u043f\u043e\u0437\u0438\u0446\u0438\u044e \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435     if('geolocation' in navigator) {       watchId = navigator.geolocation.watchPosition((position) => {       setPosition({         lat: position.coords.latitude,         lng: position.coords.longitude       })       setLocationStatus('accessed')       }, (error) => {         switch (error.code) {           case error.PERMISSION_DENIED:             setLocationStatus('denied')             break           case error.POSITION_UNAVAILABLE:             setLocationStatus('unknown')             break           case error.TIMEOUT:             setLocationStatus('error')             break           default:             setLocationStatus('error')             break         }       })       return () => {         if(watchId) {           navigator.geolocation.clearWatch(watchId)         }       }     }   }, []) ... ...<\/code><\/pre>\n<p>\u041f\u0440\u0438 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0435 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b, \u043f\u043e\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044e \u0438 \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043d\u0430 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u041d\u0430 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u0438 \u044d\u0442\u043e\u0433\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f, \u0434\u0430\u043b \u043b\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043d\u0430 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u041a\u0430\u043a \u0442\u043e\u043b\u044c\u043a\u043e \u0433\u0435\u043e\u043b\u043e\u0446\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u043e, \u043f\u043e\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043e\u0431\u044a\u0435\u043a\u0442\u0443 \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f.<\/p>\n<p>\u0421 \u043a\u043e\u0434\u043e\u043c \u043e\u0448\u0438\u0431\u043a\u0438, \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u043c \u0433\u0435\u043e\u043b\u043e\u043a\u0430\u0446\u0438\u0435\u0439, \u043c\u043e\u0436\u043d\u043e \u043b\u0435\u0433\u043a\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043e\u0448\u0438\u0431\u043a\u0443 \u0438 \u0442\u043e\u0447\u043d\u043e \u0443\u0437\u043d\u0430\u0442\u044c, \u043f\u043e\u0447\u0435\u043c\u0443 \u043d\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044e.<\/p>\n<h2>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442 \u043d\u0430 \u043a\u0430\u0440\u0442\u0435<\/h2>\n<p>\u041f\u043e\u043b\u0443\u0447\u0438\u0432 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u0438\u0445 \u0432 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 Map, \u0438 \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u043e \u043d\u0430 \u043a\u0430\u0440\u0442\u0435.<\/p>\n<p>\u041d\u0443\u0436\u043d\u043e, \u0447\u0442\u043e\u0431\u044b \u043c\u0430\u0440\u043a\u0435\u0440 \u043a\u0430\u0440\u0442\u044b \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0430\u043b\u0441\u044f \u043d\u0430 \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u044b\u0435 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u0430\u043c. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0432 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0435 Location Marker \u043f\u043e\u043c\u0435\u0449\u0435\u043d \u043c\u0435\u0442\u043e\u0434 map.flyTo, \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0439 \u0438\u043d\u0441\u0442\u0430\u043d\u0441\u043e\u043c leaflet, \u0432\u043d\u0443\u0442\u0440\u044c \u0445\u0443\u043a\u0430 useEffect \u0441 \u043f\u043e\u0437\u0438\u0446\u0438\u0435\u0439 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438. \u041f\u0440\u0438 \u043a\u0430\u0436\u0434\u043e\u043c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043c\u0430\u0440\u043a\u0435\u0440 \u0431\u0443\u0434\u0435\u0442 \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0430\u0442\u044c\u0441\u044f \u0432 \u043d\u0443\u0436\u043d\u043e\u0435 \u043c\u0435\u0441\u0442\u043e.<\/p>\n<pre><code class=\"javascript\">import { useState, useEffect } from 'react' import { MapContainer, TileLayer, useMapEvents, Marker, Popup } from 'react-leaflet' import { GeolocationPosition } from '..\/..\/..\/types'  import 'leaflet\/dist\/leaflet.css'  function Map({ location }: { location: GeolocationPosition }) {   if (!location) return 'No location found'    return (     &lt;div className='w-full bg-gray-100 h-[600px] md:h-[550px]'>       &lt;MapContainer center={[location.lat, location.lng]} zoom={30} scrollWheelZoom={true} className='h-screen'>         &lt;TileLayer           url='https:\/\/{s}.tile.openstreetmap.org\/{z}\/{x}\/{y}.png' \/\/ URL \u0441\u043b\u043e\u044f \u0442\u0430\u0439\u043b\u043e\u0432 OpenStreetMap         \/>         &lt;LocationMarker location={location} \/>       &lt;\/MapContainer>     &lt;\/div>   ) }  function LocationMarker({ location }: { location: GeolocationPosition }) {    const map = useMapEvents({})  \/\/ \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u043a\u0430\u0440\u0442\u044b \u0434\u043b\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a \u0438\u043d\u0441\u0442\u0430\u043d\u0441\u0443 \u043a\u0430\u0440\u0442\u044b Leaflet   const [position, setPosition] = useState({     lat: location.lat,     lng: location.lng   })    \/\/ \u042d\u0444\u0444\u0435\u043a\u0442 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043c\u0430\u0440\u043a\u0435\u0440\u0430 \u0438 \u043f\u0435\u0440\u0435\u043b\u0435\u0442\u0430 \u0432 \u043d\u043e\u0432\u043e\u0435 \u043c\u0435\u0441\u0442\u043e \u043f\u0440\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u043e \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0438   useEffect(() => {     setPosition({       lat: location.lat,       lng: location.lng     })     map.flyTo([location.lat, location.lng]) \/\/ \u0418\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430 \u043a\u0430\u0440\u0442\u0435   }, [location])    return position === null ? null : (     &lt;Marker position={position}>       &lt;Popup>User is here!&lt;\/Popup>     &lt;\/Marker>   ) }  export default Map<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u043e\u0442 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u043d\u0430 \u0434\u043e\u043c\u0430\u0448\u043d\u0435\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435.<\/p>\n<pre><code class=\"javascript\">export default function Home() {   const [locationStatus, setLocationStatus] = useState&lt;LocationStatus>('unknown')   const [position, setPosition] = useState&lt;GeolocationPosition | null>(null)      \/\/ ... rest  return( &lt;>   {\/** ...rest **\/}                 {             position &amp;&amp; (&lt;Map location={position}\/>)         } &lt;\/> )<\/code><\/pre>\n<h2>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0441\u043e\u043a\u0435\u0442-\u0441\u0435\u0440\u0432\u0435\u0440\u0430 node-express<\/h2>\n<p>\u0412 \u044d\u0442\u043e\u043c \u043a\u043e\u0434\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d \u043f\u0440\u043e\u0441\u0442\u043e\u0439 HTTP-\u0441\u0435\u0440\u0432\u0435\u0440, \u043d\u0430 Node.js \u0438 Express. \u0417\u0430\u0442\u0435\u043c \u0441\u043e\u0437\u0434\u0430\u043d \u0438\u043d\u0441\u0442\u0430\u043d\u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 Socket.io (\u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f io) \u0438 \u0435\u043c\u0443 \u043f\u0435\u0440\u0435\u0434\u0430\u043d \u0441\u0435\u0440\u0432\u0435\u0440 Express. \u041d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e HTTP \u0438 \u0432\u0435\u0431-\u0441\u043e\u043a\u0435\u0442\u044b \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442 \u0438\u0437 \u0441\u0435\u0431\u044f \u0440\u0430\u0437\u043d\u044b\u0435 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u044b \u0441\u0432\u044f\u0437\u0438, Socket io \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043a\u0430\u043a HTTP-\u0441\u0435\u0440\u0432\u0435\u0440\u0443, \u0442\u0430\u043a \u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0443 WebSocket \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043e\u0434\u0438\u043d \u0438 \u0442\u043e\u0442 \u0436\u0435 \u0438\u043d\u0441\u0442\u0430\u043d\u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u0430, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044f \u0438\u043c \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0447\u0435\u0440\u0435\u0437 \u043e\u0434\u0438\u043d \u0438 \u0442\u043e\u0442 \u0436\u0435 \u0441\u0435\u0442\u0435\u0432\u043e\u0439 \u043f\u043e\u0440\u0442.<\/p>\n<pre><code class=\"javascript\">import express, { Express, Request, Response } from 'express' import {Socket, Server} from 'socket.io' import cors from 'cors' import dotenv from 'dotenv'  dotenv.config()  const app: Express = express() const port = process.env.PORT || 5000  app.use(cors()) app.use(express.json())  app.get('\/', (req: Request, res: Response) => {   res.send('Welcome to LocShare!') })   const server = app.listen(port, () => {   console.log(`Server is running`) })  const io: Server = new Server(server, {   cors: {     origin: '*',   }, })  io.on('connection', (socket: Socket) => {   console.log(`User connected: ${socket.id}`) })<\/code><\/pre>\n<p>\u041a\u043e\u0433\u0434\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0434\u0435\u043b\u0438\u0442\u0441\u044f \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c, \u043f\u043e \u0441\u0443\u0442\u0438, \u0443\u0436\u0435 \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u043a\u0430\u043d\u0430\u043b.<\/p>\n<p>\u042d\u0442\u043e\u0442 \u043a\u0430\u043d\u0430\u043b \u0431\u0443\u0434\u0435\u0442 \u0438\u043c\u0435\u0442\u044c \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440. \u041a\u0430\u043a \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u0430\u043d\u0430\u043b \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u043d, \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e.<\/p>\n<p>\u0412\u043e\u0442 \u0444\u043b\u043e\u0443: <\/p>\n<ol>\n<li>\n<p>\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0434\u0435\u043b\u0438\u0442\u0441\u044f \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c: \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043a\u0430\u043d\u0430\u043b\u0430<\/p>\n<\/li>\n<li>\n<p>\u0421\u0435\u0440\u0432\u0435\u0440 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0441\u043e\u0431\u044b\u0442\u0438\u0435<\/p>\n<ol>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u0430 \u043a\u0430\u043d\u0430\u043b\u0430<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u0438\u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u043a \u043a\u0430\u043d\u0430\u043b\u0443<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u0438\u043a\u0440\u0435\u043f\u043b\u0435\u043d\u0438\u0435 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u0430 \u043a\u0430\u043d\u0430\u043b\u0430 \u043a \u0442\u0435\u043a\u0443\u0449\u0435\u043c\u0443 \u0441\u043e\u043a\u0435\u0442-\u043a\u043b\u0438\u0435\u043d\u0442\u0443<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u0438\u0432\u044f\u0437\u043a\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043a\u0430\u043d\u0430\u043b\u0430 \u0438 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u0430 \u043a\u0430\u043d\u0430\u043b\u0430<\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0441\u043e\u0437\u0434\u0430\u0442\u0435\u043b\u044f \u043a\u0430\u043d\u0430\u043b\u0430<\/p>\n<\/li>\n<\/ol>\n<\/li>\n<\/ol>\n<p>\u0417\u0434\u0435\u0441\u044c \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u0435\u0442\u0441\u044f \u0441\u043e\u043a\u0435\u0442. \u041a \u043d\u0435\u043c\u0443 \u043f\u0440\u0438\u0441\u043e\u0435\u0434\u0438\u043d\u044f\u0435\u0442\u0441\u044f \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e \u043f\u043e\u0434 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c roomId. \u041f\u043e\u0437\u0436\u0435 \u043e\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u043e \u043f\u0440\u0438 \u0432\u044b\u0445\u043e\u0434\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438\u0437 \u043a\u0430\u043d\u0430\u043b\u0430.<\/p>\n<pre><code class=\"javascript\">\/\/ \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430, \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u044e\u0449\u0435\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 Socket interface CustomSocket extends Socket {   roomId?: string } const roomCreator = new Map&lt;string, string>() \/\/ roomid => socketid  io.on('connection', (socket: CustomSocket) => {   console.log(`User connected: ${socket.id}`)    socket.on('createRoom', (data) => {     const roomId = Math.random().toString(36).substring(2, 7)     socket.join(roomId) \/\/ \u043f\u0440\u0438\u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u043a \u043a\u0430\u043d\u0430\u043b\u0443 \u0432 \u0441\u043e\u043a\u0435\u0442\u0430\u0445         socket.roomId = roomId \/\/  \u043f\u0440\u0438\u0441\u0432\u0430\u0438\u0432\u0430\u043d\u0438\u0435 roomId \u0441\u043e\u043a\u0435\u0442\u0443     const totalRoomUsers = io.sockets.adapter.rooms.get(roomId)     socket.emit('roomCreated', {        roomId,       position: data.position,       totalConnectedUsers: Array.from(totalRoomUsers || []),     })     roomCreator.set(roomId, socket.id) \/\/ \u043c\u0430\u043f\u043f\u0438\u043d\u0433 roomid \u0441 \u0441\u043e\u043a\u0435\u0442\u043e\u043c   }) })<\/code><\/pre>\n<p><strong>\u041f\u0440\u0438\u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u043a \u043a\u0430\u043d\u0430\u043b\u0443<\/strong><\/p>\n<p>\u0427\u0442\u043e\u0431\u044b \u043f\u0440\u0438\u0441\u043e\u0435\u0434\u0438\u043d\u0438\u0442\u044c\u0441\u044f \u043a \u043a\u0430\u043d\u0430\u043b\u0443 \u043a\u043b\u0438\u0435\u043d\u0442 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 joinRoom \u0441 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u043e\u043c \u043a\u0430\u043d\u0430\u043b\u0430.<\/p>\n<ol>\n<li>\n<p>\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442 \u00abjoinRoom\u00bb \u0441 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u043e\u043c \u043a\u0430\u043d\u0430\u043b\u0430<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u043b\u0438 \u043a\u0430\u043d\u0430\u043b:<\/p>\n<ol>\n<li>\n<p>\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442<\/p>\n<ol>\n<li>\n<p>\u041f\u0440\u0438\u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u043a \u043a\u0430\u043d\u0430\u043b\u0443<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u0438\u0441\u0432\u043e\u0435\u043d\u0438\u0435 roomid \u0441\u043e\u043a\u0435\u0442\u0443<\/p>\n<\/li>\n<li>\n<p>\u0423\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0435 \u0441\u043e\u0437\u0434\u0430\u0442\u0435\u043b\u044e \u043a\u0430\u043d\u0430\u043b\u0430<\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0442\u043e\u043c\u0443, \u043a\u0442\u043e \u043f\u0440\u0438\u0441\u043e\u0435\u0434\u0438\u043d\u0438\u043b\u0441\u044f (\u0441\u043e\u043a\u0435\u0442)<\/p>\n<\/li>\n<\/ol>\n<\/li>\n<li>\n<p>!\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442<\/p>\n<ol>\n<li>\n<p>\u0423\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0435 \u0441\u043e\u043a\u0435\u0442\u0430<\/p>\n<\/li>\n<\/ol>\n<\/li>\n<\/ol>\n<\/li>\n<\/ol>\n<pre><code class=\"javascript\">... ... socket.on('joinRoom', (data: {roomId: string}) => {      \/\/ \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u043d\u0438\u044f \u043a\u0430\u043d\u0430\u043b\u0430     const roomExists = io.sockets.adapter.rooms.has(data.roomId)     if (roomExists) {       socket.join(data.roomId)       socket.roomId = data.roomId \/\/  \u041f\u0440\u0438\u0441\u0432\u043e\u0435\u043d\u0438\u0435 roomid \u0441\u043e\u043a\u0435\u0442\u0443        \/\/ \u0423\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0435 \u0441\u043e\u0437\u0434\u0430\u0442\u0435\u043b\u044e \u043a\u0430\u043d\u0430\u043b\u0430            const creatorSocketID = roomCreator.get(data.roomId)       if (creatorSocketID) {         const creatorSocket = io.sockets.sockets.get(creatorSocketID) \/\/ \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0438\u043d\u0441\u0442\u0430\u043d\u0441\u0430 \u0441\u043e\u043a\u0435\u0442\u0430 \u0441\u043e\u0437\u0434\u0430\u0442\u0435\u043b\u044f         if (creatorSocket) {           const totalRoomUsers = io.sockets.adapter.rooms.get(data.roomId)           creatorSocket.emit('userJoinedRoom', {             userId: socket.id,             totalConnectedUsers: Array.from(totalRoomUsers || [])           })         }       }       \/\/ \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043f\u0440\u0438\u0441\u043e\u0435\u0434\u0438\u043d\u0438\u0432\u0448\u0435\u043c\u0443\u0441\u044f       io.to(`${socket.id}`).emit('roomJoined', {         status: 'OK',       })      } else {       io.to(`${socket.id}`).emit('roomJoined', {         status: 'ERROR'       })     }   })<\/code><\/pre>\n<p>\u041e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u043b\u043e\u043a\u0430\u0446\u0438\u0438<\/p>\n<pre><code class=\"javascript\">socket.on('updateLocation', (data) => {     io.emit('updateLocationResponse', data) })<\/code><\/pre>\n<h2>\u0414\u043e\u043c\u0430\u0448\u043d\u044f\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430: \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0441\u043e\u043a\u0435\u0442\u043e\u0432 \u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043a\u0430\u043d\u0430\u043b\u0430<\/h2>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0441 \u0434\u043e\u043c\u0430\u0448\u043d\u0435\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043a \u0441\u043e\u043a\u0435\u0442-\u0441\u0435\u0440\u0432\u0435\u0440\u0443. \u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0434\u043e\u043b\u0436\u0435\u043d \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u043e\u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f \u0441\u0432\u043e\u0438\u043c \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c. \u041f\u043e\u0441\u043b\u0435 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0442\u044c\u0441\u044f \u043a \u0441\u0435\u0440\u0432\u0435\u0440\u0443. \u041f\u043e\u0441\u043b\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0433\u043e \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u0441\u043e\u0431\u044b\u0442\u0438\u0435 createRoom.<\/p>\n<p>\u042d\u0442\u043e\u0442 \u043f\u043e\u0434\u0445\u043e\u0434 \u0431\u044b\u043b \u0432\u044b\u0431\u0440\u0430\u043d \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0435\u0434\u043e\u0442\u0432\u0440\u0430\u0442\u0438\u0442\u044c \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043a \u0441\u0435\u0440\u0432\u0435\u0440\u0443 \u043f\u0440\u0438 \u043f\u043e\u0441\u0435\u0449\u0435\u043d\u0438\u0438 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u043c. \u0412 \u0431\u0443\u0434\u0443\u0449\u0435\u043c \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u043c\u043e\u0433\u0443\u0442 \u043f\u043e\u044f\u0432\u0438\u0442\u044c\u0441\u044f \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b, \u0442\u0430\u043a\u0438\u0435 \u043a\u0430\u043a \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u0432\u0445\u043e\u0434\u0430 \u0438\u043b\u0438 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438. \u0427\u0442\u043e\u0431\u044b \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u043d\u0435\u043d\u0443\u0436\u043d\u044b\u0445 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0439, \u0432\u0441\u0435 \u0431\u044b\u043b\u043e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u043e \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0447\u0442\u043e\u0431\u044b \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u044c \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f.<\/p>\n<pre><code class=\"javascript\">type SocketStatus = 'connecting' | 'connected' | 'disconnected' | 'error' type RoomInfo = {   roomId: string   position: GeolocationPosition   totalConnectedUsers: string[] }  export default function Home() {     \/\/ \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f, \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0435 \u0441 \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c    const {socket, connectSocket} = useSocket()   const [socketStatus, setSocketStatus] = useState&lt;SocketStatus>('disconnected')     const [roomLink, setRoomLink] = useState&lt;string>('')     const [roomInfo, setRoomInfo] = useState&lt;RoomInfo | null>(null)    function connectToSocketServer() {     connectSocket()     setSocketStatus('connecting')   }    useEffect(() => {     let watchId: number | null = null     \/\/ \u043b\u043e\u0433\u0438\u043a\u0430 \u043b\u0435\u043e\u043b\u043e\u043a\u0430\u0446\u0438\u0438   }, [])    useEffect(() => {     if(socket) {       socket.on('connect', () => {         setSocketStatus('connected')         socket.emit('createRoom', {           position         })       })        socket.on('roomCreated', (data: RoomInfo) => {         toast.success('You are live!', {           autoClose: 2000,           })         setRoomInfo(data)       })        socket.on('userJoinedRoom', (data: {userId: string, totalConnectedUsers: string[]}) => {         setRoomInfo((prev) => {           if(prev) {             return {               ...prev,               totalConnectedUsers: data.totalConnectedUsers             }           }           return null         })          toast.info(`${data.userId} joined the room`, {           autoClose: 2000,         })          position &amp;&amp; socket.emit('updateLocation', {           position         })       })        socket.on('disconnect', () => {         setSocketStatus('disconnected')       })     }   }, [socket])    useEffect(() => {     if(socket) {       socket.emit('updateLocation', {         position       })     }   }, [position])     return (     &lt;>             {\/* ...rest *\/}             {               socketStatus === 'disconnected' &amp;&amp; (                 &lt;div className='flex flex-col gap-6 items-start w-full'>                   &lt;button                      className={`${locationStatus === 'accessed' ? 'bg-purple-800' : 'bg-gray-600 cursor-not-allowed'}`}                     onClick={() => {                       if(locationStatus === 'accessed') {                         connectToSocketServer()                       } else {                         toast.error('Please allow location access', {                           autoClose: 2000,                         })                       }                     }}                     disabled={locationStatus !== 'accessed'}                     >Share Location&lt;\/button>                   {\/*  ...rest *\/}               &lt;\/div>               )<\/code><\/pre>\n<h2>\u0421\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f: \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u0443 \u043a\u0430\u043d\u0430\u043b\u0430 \u0438 \u043f\u0440\u0438\u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u043a \u043a\u0430\u043d\u0430\u043b\u0443<\/h2>\n<p>\u041a\u043e\u0433\u0434\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442\u0441\u044f, \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u0435\u0442\u0441\u044f \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u043a\u0430\u043d\u0430\u043b\u0430 \u0438\u0437 URL. \u0412\u043f\u043e\u0441\u043b\u0435\u0434\u0441\u0442\u0432\u0438\u0438 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0441 \u0441\u043e\u043a\u0435\u0442\u043e\u043c. \u041f\u043e\u0441\u043b\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0433\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u00abjoin room\u00bb, \u0447\u0442\u043e\u0431\u044b \u0443\u043a\u0430\u0437\u0430\u0442\u044c, \u0447\u0442\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043f\u0440\u0438\u0441\u043e\u0435\u0434\u0438\u043d\u0438\u043b\u0441\u044f \u043a \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0439 \u043a\u043e\u043c\u043d\u0430\u0442\u0435.<\/p>\n<pre><code class=\"javascript\">import React, {useState, useEffect} from 'react' import { useParams } from 'react-router-dom' import {useSocket} from '..\/context\/socket'  type RoomStatus = 'unknown' | 'joined' | 'not-exist'  function Location() {   const { roomId } = useParams()   const { socket, connectSocket } = useSocket()   const [socketStatus, setSocketStatus] = useState&lt;SocketStatus>('disconnected')   const [roomStatus, setRoomStatus] = useState&lt;RoomStatus>('unknown')   const [position, setPosition] = useState&lt;GeolocationPosition | null>(null)    useEffect(() => {     connectSocket()     setSocketStatus('connecting')     return () => {       if(socket) {         socket.disconnect()         setSocketStatus('disconnected')       }     }   }, [])    useEffect(() => {      if(socket){              socket.on('connect', () => {         setSocketStatus('connected')         socket.emit('joinRoom', {           roomId         })       })        socket.on('roomJoined', ({status}: {status: string}) => {         if(status === 'OK') {           setRoomStatus('joined')         } else if (status === 'ERROR') {           setRoomStatus('not-exist')         } else {           setRoomStatus('unknown')         }       })        socket.on('updateLocationResponse', ({position}:{position: GeolocationPosition}) => {         if(position) {           setPosition(position)         }       })        socket.on('disconnect', () => {         setSocketStatus('disconnected')       })     }    }, [socket])  \/\/ ...rest<\/code><\/pre>\n<h2>\u0421\u0435\u0440\u0432\u0435\u0440: \u0432\u044b\u0445\u043e\u0434 \u0438\u0437 \u043a\u0430\u043d\u0430\u043b\u0430<\/h2>\n<p>\u0412\u043e\u0442 \u043b\u043e\u0433\u0438\u043a\u0430, \u043a\u043e\u0433\u0434\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043f\u043e\u043a\u0438\u0434\u0430\u0435\u0442 \u043a\u043e\u043c\u043d\u0430\u0442\u0443:<\/p>\n<p>\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043f\u043e\u043a\u0438\u0434\u0430\u0435\u0442 \u043a\u0430\u043d\u0430\u043b:<\/p>\n<ol>\n<li>\n<p>\u0414\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u0442\u0435\u043b\u044f \u043a\u0430\u043d\u0430\u043b\u0430:<\/p>\n<ol>\n<li>\n<p>\u0415\u0441\u043b\u0438 \u0443\u0445\u043e\u0434\u044f\u0449\u0438\u0439 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u043e\u0437\u0434\u0430\u0442\u0435\u043b\u0435\u043c:<\/p>\n<ol>\n<li>\n<p>\u0417\u0430\u043a\u0440\u044b\u0442\u0438\u0435 \u043a\u0430\u043d\u0430\u043b\u0430<\/p>\n<\/li>\n<li>\n<p>\u0423\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0435 \u0434\u0440\u0443\u0433\u0438\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439<\/p>\n<\/li>\n<\/ol>\n<\/li>\n<\/ol>\n<\/li>\n<li>\n<p>\u0414\u043b\u044f \u0433\u043e\u0441\u0442\u044f \u043a\u0430\u043d\u0430\u043b\u0430:<\/p>\n<ol>\n<li>\n<p>\u0415\u0441\u043b\u0438 \u0443\u0445\u043e\u0434\u044f\u0449\u0438\u0439 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0433\u043e\u0441\u0442\u0435\u043c:<\/p>\n<ol>\n<li>\n<p>\u0423\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0435 \u0441\u043e\u0437\u0434\u0430\u0442\u0435\u043b\u044e:<\/p>\n<ol>\n<li>\n<p>\u041d\u043e\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u0441\u043e\u0437\u0434\u0430\u0442\u0435\u043b\u044e \u043a\u043e\u043c\u043d\u0430\u0442\u044b \u043e\u0431 \u0443\u0445\u043e\u0434\u0435.<\/p>\n<\/li>\n<\/ol>\n<\/li>\n<li>\n<p>\u0412\u044b\u0445\u043e\u0434 \u0438\u0437 \u043a\u0430\u043d\u0430\u043b\u0430:<\/p>\n<ol>\n<li>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u0443\u0448\u0435\u0434\u0448\u0438\u0439 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0443\u0434\u0430\u043b\u0435\u043d \u0438\u0437 \u0441\u043f\u0438\u0441\u043a\u0430 \u0443\u0447\u0430\u0441\u0442\u043d\u0438\u043a\u043e\u0432 \u043a\u043e\u043c\u043d\u0430\u0442\u044b.<\/p>\n<\/li>\n<\/ol>\n<\/li>\n<\/ol>\n<\/li>\n<\/ol>\n<\/li>\n<\/ol>\n<pre><code class=\"javascript\">io.on('connection', (socket: CustomSocket) => {   console.log(`User connected: ${socket.id}`)  \/\/ ...rest code  socket.on('disconnect', () => {     console.log(`User disconnected: ${socket.id}`)      const roomId = socket.roomId     if(roomId){       \/\/ \u0423\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u043a\u043e\u043c\u043d\u0430\u0442\u044b \u043f\u0440\u0438 \u0432\u044b\u0445\u043e\u0434\u0435 \u0441\u043e\u0437\u0434\u0430\u0442\u0435\u043b\u044f       if(roomCreator.get(roomId) === socket.id){         \/\/ \u0423\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0435 \u0433\u043e\u0441\u0442\u044f\u043c \u043e\u0431 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0438         const roomUsers = io.sockets.adapter.rooms.get(roomId)         if(roomUsers){           for (const socketId of roomUsers) {             io.to(`${socketId}`).emit('roomDestroyed', {               status: 'OK'             })           }         }         io.sockets.adapter.rooms.delete(roomId)         roomCreator.delete(roomId)           } else{         socket.leave(roomId)         \/\/ \u0423\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0435 \u0441\u043e\u0437\u0434\u0430\u0442\u0435\u043b\u044e \u043e \u0432\u044b\u0445\u043e\u0434\u0435 \u0433\u043e\u0441\u0442\u044f         const creatorSocketId = roomCreator.get(roomId)         if(creatorSocketId){           const creatorSocket = io.sockets.sockets.get(creatorSocketId)           if(creatorSocket){             creatorSocket.emit('userLeftRoom', {               userId: socket.id,               totalConnectedUsers: Array.from(io.sockets.adapter.rooms.get(roomId) || [])             })           }         }       }     }    })  })<\/code><\/pre>\n<h2>\u041e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0434\u043e\u043c\u0430\u0448\u043d\u0435\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u0438 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f: \u0432\u044b\u0445\u043e\u0434 \u0438\u0437 \u043a\u043e\u043c\u043d\u0430\u0442\u044b<\/h2>\n<p>home.tsx<\/p>\n<pre><code class=\"javascript\">export default function Home() {      \/\/ ...rest    useEffect(() => {     if(socket) {       socket.on('connect', () => {         setSocketStatus('connected')         socket.emit('createRoom', {           position         })       })             \/\/ ...rest              socket.on('userLeftRoom', (data: {userId: string, totalConnectedUsers: string[]}) => {         setRoomInfo((prev) => {           if(prev) {             return {                 ...prev,                 totalConnectedUsers: data.totalConnectedUsers               }             }             return null           })           toast.info(`${data.userId} left the room`, {             autoClose: 2000,           })       })        socket.on('disconnect', () => {         setSocketStatus('disconnected')       })     }   }, [socket]) \/\/ ...rest<\/code><\/pre>\n<p>location.tsx<\/p>\n<pre><code class=\"javascript\">function Location() {    \/\/ ...rest    useEffect(() => {      if(socket){              socket.on('connect', () => {         setSocketStatus('connected')         socket.emit('joinRoom', {           roomId         })       })        \/\/ ...rest              socket.on('roomDestroyed', () => {         setRoomStatus('not-exist')         socket.disconnect()       })        socket.on('disconnect', () => {         setSocketStatus('disconnected')       })     }    }, [socket])  function stopSharingLocation() {     if(socket){       socket.disconnect()       setSocketStatus('disconnected')       setRoomInfo(null)       toast.success('You are no longer live!', {         autoClose: 2000,       })     }   }  \/\/ ...rest<\/code><\/pre>\n<h2>\u0412\u0441\u0451<\/h2>\n<p>\u041c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043b\u0438 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0438 \u043b\u043e\u0433\u0438\u043a\u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u043e\u0431\u043c\u0435\u043d\u0430 \u0433\u0435\u043e\u0434\u0430\u043d\u043d\u044b\u043c\u0438, \u0441\u043e\u0441\u0440\u0435\u0434\u043e\u0442\u043e\u0447\u0438\u0432 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u0430\u0441\u043f\u0435\u043a\u0442\u0430\u0445. \u042f \u043d\u0435 \u0434\u0435\u043b\u0438\u043b\u0441\u044f \u043a\u043e\u0434\u043e\u043c \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 JSX \u0438 \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, \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043d\u0430\u0439\u0442\u0438 \u043f\u043e\u043b\u043d\u044b\u0439 \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434 \u0432 <a href=\"https:\/\/github.com\/manish-mehra\/locshare\" rel=\"noopener noreferrer nofollow\">\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438 GitHub<\/a>.<\/p>\n<p>PR\u044b \u043f\u0440\u0438\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0442\u0441\u044f, \u0435\u0441\u043b\u0438 \u0437\u0430\u0445\u043e\u0447\u0435\u0442\u0441\u044f \u043f\u043e\u0443\u0447\u0430\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c!<\/p>\n<hr\/>\n<p>\u0421\u043f\u0430\u0441\u0438\u0431\u043e <a class=\"mention\" href=\"\/users\/r1ndaman\">@r1ndaman<\/a> \u0437\u0430 \u0440\u0435\u0434\u0430\u043a\u0442\u0443\u0440\u0443 \u0441\u0442\u0430\u0442\u044c\u0438.<\/p>\n<\/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\/770066\/\"> https:\/\/habr.com\/ru\/articles\/770066\/<\/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<p>\u0415\u0441\u0442\u044c \u043c\u043d\u043e\u0433\u043e \u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043d\u0430 React \u0438 Socket.io. \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0442\u0430\u043a\u0438\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u043f\u043e\u043b\u0435\u0437\u043d\u043e \u0434\u043b\u044f \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f, \u043d\u043e \u043c\u043d\u0435 \u0437\u0430\u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0447\u0435\u0433\u043e-\u0442\u043e \u0431\u043e\u043b\u0435\u0435 \u0442\u0432\u043e\u0440\u0447\u0435\u0441\u043a\u043e\u0433\u043e. \u041f\u0440\u0438\u0448\u043b\u0430 \u0438\u0434\u0435\u044f \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u0433\u0434\u0435 \u043c\u043e\u0436\u043d\u043e \u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c.<\/p>\n<p>\u0418\u0442\u0430\u043a, \u043d\u0430\u0447\u043d\u0435\u043c.<\/p>\n<details class=\"spoiler\">\n<summary>\u041d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u043a\u0440\u0438\u043d\u043e\u0432 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c, \u0438 GitHub<\/summary>\n<div class=\"spoiler__content\">\n<figure class=\"full-width\"><\/figure>\n<figure class=\"full-width\"><\/figure>\n<figure class=\"full-width\"><\/figure>\n<figure class=\"full-width\"><\/figure>\n<p>\u041c\u043e\u0436\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f, \u043a\u043e\u0433\u0434\u0430 \u043a\u0442\u043e-\u0442\u043e \u043f\u0440\u0438\u0441\u043e\u0435\u0434\u0438\u043d\u044f\u0435\u0442\u0441\u044f \u0438\u043b\u0438 \u0443\u0445\u043e\u0434\u0438\u0442 \u0438\u0437 \u043a\u0430\u043d\u0430\u043b\u0430, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0432\u0438\u0434\u0435\u0442\u044c \u0442\u0435\u043a\u0443\u0449\u0435\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439, \u043d\u0430\u0445\u043e\u0434\u044f\u0449\u0438\u0445\u0441\u044f \u0432 \u0441\u0435\u0442\u0438.<\/p>\n<p>\u041a\u0430\u043a \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0443\u043d\u0435\u0440 \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u0435\u0442 \u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f \u0441\u0432\u043e\u0438\u043c \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c, \u043a\u0430\u043d\u0430\u043b \u0443\u0434\u0430\u043b\u044f\u0435\u0442\u0441\u044f, \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 \u043d\u0435 \u043c\u043e\u0433\u0443\u0442 \u0432\u0438\u0434\u0435\u0442\u044c \u043b\u043e\u043a\u0430\u0446\u0438\u044e.<\/p>\n<p>\u0422\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043c\u043e\u0436\u043d\u043e \u043d\u0435 \u0432\u044b\u0445\u043e\u0434\u044f \u043d\u0430 \u0443\u043b\u0438\u0446\u0443 (\u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f).<\/p>\n<figure class=\"full-width\"><\/figure>\n<figure class=\"full-width\"><\/figure>\n<p>GitHub: <a href=\"https:\/\/github.com\/manish-mehra\/locshare\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/manish-mehra\/locshare<\/a><\/p>\n<\/div>\n<\/details>\n<h2>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/h2>\n<p>\u041d\u0430 \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434\u0435 \u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u043b React-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c Vite, TypeScript \u0438 Tailwind CSS. \u0414\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442 \u043d\u0430 \u043a\u0430\u0440\u0442\u0435 \u044f \u0432\u0437\u044f\u043b \u0438\u0437\u0432\u0435\u0441\u0442\u043d\u0443\u044e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 \u0441 \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u043c \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u043c \u043a\u043e\u0434\u043e\u043c \u043f\u043e\u0434 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c Leaflet.<\/p>\n<p>\u042f \u043d\u0435\u0434\u0430\u0432\u043d\u043e \u043d\u0430\u0447\u0430\u043b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c TypeScript \u0438 \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u043b \u0435\u0433\u043e \u0432 \u044d\u0442\u043e\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435. \u041e\u0434\u043d\u0430\u043a\u043e \u0432\u0430\u0436\u043d\u043e \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e TypeScript \u043d\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u043c \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u043c.<\/p>\n<p>\u0412\u043e\u0442 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434\u0430:<\/p>\n<pre><code class=\"javascript\">{   \"name\": \"client\",   \"private\": true,   \"version\": \"0.0.0\",   \"type\": \"module\",   \"scripts\": {     \"dev\": \"vite\",     \"build\": \"tsc &amp;&amp; vite build\",     \"lint\": \"eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0\",     \"preview\": \"vite preview\"   },   \"dependencies\": {     \"@types\/leaflet\": \"^1.9.6\",     \"@types\/react-leaflet\": \"^3.0.0\",     \"react\": \"^18.2.0\",     \"react-dom\": \"^18.2.0\",     \"react-icons\": \"^4.11.0\",     \"react-leaflet\": \"^4.2.1\",     \"react-router-dom\": \"^6.16.0\",     \"react-toastify\": \"^9.1.3\",     \"socket.io-client\": \"^4.7.2\"   },   \"devDependencies\": {     \"@types\/react\": \"^18.2.15\",     \"@types\/react-dom\": \"^18.2.7\",     \"@typescript-eslint\/eslint-plugin\": \"^6.0.0\",     \"@typescript-eslint\/parser\": \"^6.0.0\",     \"@vitejs\/plugin-react\": \"^4.0.3\",     \"autoprefixer\": \"^10.4.15\",     \"eslint\": \"^8.45.0\",     \"eslint-plugin-react-hooks\": \"^4.6.0\",     \"eslint-plugin-react-refresh\": \"^0.4.3\",     \"postcss\": \"^8.4.29\",     \"tailwindcss\": \"^3.3.3\",     \"typescript\": \"^5.0.2\",     \"vite\": \"^4.4.5\"   } }<\/code><\/pre>\n<p>\u0414\u043b\u044f \u0431\u044d\u043a\u0435\u043d\u0434\u0430 \u0435\u0441\u0442\u044c \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u0441\u0435\u0440\u0432\u0435\u0440 node-express \u0441\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c\u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044f\u043c\u0438:<\/p>\n<pre><code class=\"javascript\">{   \"name\": \"server\",   \"version\": \"1.0.0\",   \"description\": \"\",   \"main\": \"index.js\",   \"scripts\": {     \"test\": \"echo \\\"Error: no test specified\\\" &amp;&amp; exit 1\",     \"build\": \"tsc\",     \"start\": \"node dist\/index.js\",     \"dev\": \"concurrently \\\"npx tsc --watch\\\" \\\"nodemon -q dist\/index.js\\\"\"   },   \"keywords\": [],   \"author\": \"\",   \"license\": \"ISC\",   \"dependencies\": {     \"cors\": \"^2.8.5\",     \"dotenv\": \"^16.3.1\",     \"express\": \"^4.18.2\",     \"socket.io\": \"^4.7.2\"   },   \"devDependencies\": {     \"@types\/express\": \"^4.17.17\",     \"concurrently\": \"^8.2.0\",     \"nodemon\": \"^3.0.1\",     \"typescript\": \"^5.2.2\"   } }<\/code><\/pre>\n<h2>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0430\u043f\u043e\u043a <\/h2>\n<p>React:<\/p>\n<pre><code class=\"javascript\">? src \u251c\u2500\u2500 ? components \u2502   \u251c\u2500\u2500 ? Element \u2502   \u2502   \u251c\u2500\u2500 ? Header \u2502   \u2502   \u251c\u2500\u2500 ? Map \u2502   \u2502   \u251c\u2500\u2500 ? Status \u2502   \u2502   \u251c\u2500\u2500 ? StatusPanel \u2502   \u251c\u2500\u2500 ? Layout \u251c\u2500\u2500 ? context \u2502   \u251c\u2500\u2500 ? socket.tsx \u251c\u2500\u2500 ? pages \u2502   \u251c\u2500\u2500 ? Home.tsx \u2502   \u251c\u2500\u2500 ? Location.tsx \u251c\u2500\u2500 ? types \u251c\u2500\u2500 ? App.tsx \u251c\u2500\u2500 ? main.tsx \u251c\u2500\u2500 ? index.css ...rest<\/code><\/pre>\n<p>Node:<\/p>\n<pre><code class=\"javascript\">? src \u251c\u2500\u2500 ? index.ts<\/code><\/pre>\n<h2>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 Socket Context<\/h2>\n<p>\u0421\u043e\u0445\u0440\u0430\u043d\u044f\u044f \u0441\u043e\u043a\u0435\u0442 \u0432 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435, \u0435\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u043c \u0434\u043b\u044f \u0432\u0441\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0424\u0443\u043d\u043a\u0446\u0438\u044f connectSocket \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435. \u0415\u0441\u043b\u0438 \u0441\u043e\u043a\u0435\u0442 &#8212; null (\u043d\u0435\u0442 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0433\u043e \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f), \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u043d\u043e\u0432\u043e\u0435 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0441\u043e\u043a\u0435\u0442\u0430. \u0415\u0441\u043b\u0438 \u0441\u043e\u043a\u0435\u0442 &#8212; \u043d\u0435 null (\u043e\u0442\u043a\u043b\u044e\u0447\u0435\u043d), \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u043a \u0441\u043e\u043a\u0435\u0442\u0443.<\/p>\n<pre><code class=\"javascript\">\/\/ SocketProvider.js import {useState, createContext, useContext, JSX} from 'react' import {io, Socket} from 'socket.io-client' import { SOCKET_URL } from '..\/config'  type SocketContextType = {   socket: Socket | null;   connectSocket: () => void; }  type SocketProviderProps = {   children: JSX.Element }  export const SocketContext = createContext&lt;SocketContextType | null>(null)  export const SocketProvider = ({children}: SocketProviderProps) => {   const [socket, setSocket] = useState&lt;Socket | null>(null)    const connectSocket = () => {     if(!socket) {       const newSocket: Socket = io(SOCKET_URL)       setSocket(newSocket)       return     }     socket.connect()   }    return (     &lt;SocketContext.Provider value={{socket, connectSocket}}>       {children}     &lt;\/SocketContext.Provider>   ) }  export const useSocket = () => {   const context = useContext(SocketContext)   if(!context) {     throw new Error('Something went wrong!')   }   return context }<\/code><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u0431\u044b\u043b\u0438 \u0441\u0434\u0435\u043b\u0430\u043d\u044b \u0443\u043f\u0440\u043e\u0449\u0435\u043d\u0438\u044f. \u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0439 \u0445\u0443\u043a useSocket, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u043b\u043e\u0433\u0438\u043a\u0443 \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a SocketContext \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 SocketProvider. \u0422\u0430\u043a\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u0443\u043f\u0440\u043e\u0449\u0430\u0435\u0442 \u043a\u043e\u0434, \u0434\u0435\u043b\u0430\u044f \u0435\u0433\u043e \u0431\u043e\u043b\u0435\u0435 \u0447\u0438\u0442\u0430\u0435\u043c\u044b\u043c \u0438 \u043f\u043e\u043d\u044f\u0442\u043d\u044b\u043c \u043f\u0440\u0438 \u0440\u0430\u0431\u043e\u0442\u0435 \u0441\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u043c\u0438 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430  \u0432 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430\u0445.<\/p>\n<h2>\u041e\u0431\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043e\u043c \u0441\u043e\u043a\u0435\u0442\u0430<\/h2>\n<pre><code class=\"javascript\">import React from 'react' import ReactDOM from 'react-dom\/client' import App from '.\/App.tsx' import '.\/index.css' import { SocketProvider } from '.\/context\/socket.tsx' import {ToastContainer} from 'react-toastify'  ReactDOM.createRoot(document.getElementById('root')!).render(   &lt;React.StrictMode>     &lt;SocketProvider>       &lt;>         &lt;App \/>         &lt;ToastContainer newestOnTop\/>       &lt;\/>     &lt;\/SocketProvider>   &lt;\/React.StrictMode>, )<\/code><\/pre>\n<h2>\u0420\u043e\u0443\u0442\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f<\/h2>\n<p>\u0417\u0434\u0435\u0441\u044c \u0435\u0441\u0442\u044c \u0434\u0432\u0435 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b: home \u0438 location. \u0412 home \u043c\u043e\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043a\u0430\u043d\u0430\u043b \u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435. \u0421\u0442\u0440\u0430\u043d\u0438\u0446\u0430 location \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u0442\u0441\u044f, \u043a\u043e\u0433\u0434\u0430 URL \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0448\u0430\u0431\u043b\u043e\u043d\u0443 \/location\/1242, \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u044f, \u0447\u0442\u043e 1242 &#8212; \u044d\u0442\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0439 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u043a\u0430\u043d\u0430\u043b\u0430 \u0438\u043b\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440.<\/p>\n<p>\u042d\u0442\u0438 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u043e\u0431\u0435\u0440\u043d\u0443\u0442\u044b \u0432 Layout Component.<\/p>\n<pre><code class=\"javascript\">import { BrowserRouter, Routes, Route } from 'react-router-dom' import Layout from '.\/components\/Layout' import Home from '.\/pages\/Home' import Location from '.\/pages\/Location'  function App() {    return (     &lt;BrowserRouter>       &lt;Routes>         &lt;Route path=\"\/\" element={&lt;Layout \/>}>           &lt;Route index element={&lt;Home \/>} \/>           &lt;Route path=\"location\/:roomId\" element={&lt;Location \/>}\/>         &lt;\/Route>       &lt;\/Routes>     &lt;\/BrowserRouter>   ) }  export default App<\/code><\/pre>\n<p>Layout Component<\/p>\n<pre><code class=\"javascript\">import { Outlet } from 'react-router-dom' import Header from '..\/Elements\/Header'  function index() {   return (     &lt;div className='flex justify-center px-3 py-2'>       &lt;div className='flex flex-col w-full md:min-w-full xl:min-w-[1100px] xl:max-w-[1200px] mb-4'>         &lt;Header \/>         &lt;main>           &lt;Outlet \/>         &lt;\/main>       &lt;\/div>     &lt;\/div>   ) }  export default index<\/code><\/pre>\n<h2>\u0414\u043e\u0441\u0442\u0443\u043f \u043a \u043b\u043e\u043a\u0430\u0446\u0438\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f<\/h2>\n<p>\u0414\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0433\u0435\u043e\u043b\u043e\u043a\u0430\u0446\u0438\u0438, \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c\u044b\u0439 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u043c. \u042d\u0442\u043e \u0432\u044b\u0437\u043e\u0432\u0435\u0442 \u0432\u0441\u043f\u043b\u044b\u0432\u0430\u044e\u0449\u0435\u0435 \u043e\u043a\u043d\u043e, \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u044e\u0449\u0435\u0435 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043d\u0430 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044e.<\/p>\n<pre><code class=\"javascript\">\/\/ \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0442\u0435\u043a\u0443\u0449\u0443\u044e \u043b\u043e\u043a\u0430\u0446\u0438\u044e navigator.geolocation.getCurrentPosition(success, error, options)<\/code><\/pre>\n<p>success, error (\u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e), options (\u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e) \u2014 \u044d\u0442\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0435\u043c\u044b\u0435 \u043a\u043e\u043b\u043b\u0431\u044d\u043a-\u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u0438 \u0447\u0435\u0440\u0435\u0437 \u043d\u0438\u0445 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u0430\u043c \u0438\u043b\u0438 \u043e\u0448\u0438\u0431\u043a\u0435 \u0438\u043b\u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b. \u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 \u0432 <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/Geolocation\/getCurrentPosition\" rel=\"noopener noreferrer nofollow\">\u0434\u043e\u043a\u0435 Mozilla<\/a>.<\/p>\n<p>\u041f\u0440\u043e\u0441\u0442\u043e \u0442\u0435\u043a\u0443\u0449\u0430\u044f \u043f\u043e\u0437\u0438\u0446\u0438\u044f \u043d\u0435 \u043d\u0443\u0436\u043d\u0430. \u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0438\u043c\u0435\u043d\u043d\u043e \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0442\u044c \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438\u0437 \u0442\u043e\u0447\u043a\u0438 \u0410 \u0432 \u0442\u043e\u0447\u043a\u0443 \u0411.<\/p>\n<p>\u041c\u044b \u043c\u043e\u0433\u043b\u0438 \u0431\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e setInterval, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043d\u0435\u043e\u0434\u043d\u043e\u043a\u0440\u0430\u0442\u043d\u043e \u0431\u044b \u0432\u044b\u0437\u044b\u0432\u0430\u043b\u0430 getCurrentPosition(). \u041d\u043e \u043e\u043d\u0430 \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0433\u0435\u043e\u043b\u043e\u043a\u0430\u0446\u0438\u0438 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0434\u0440\u0443\u0433\u043e\u0439 \u043c\u0435\u0442\u043e\u0434, watchPosition(). \u0418 \u044d\u0442\u043e\u0442 \u043c\u0435\u0442\u043e\u0434 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437, \u043a\u043e\u0433\u0434\u0430 \u043f\u043e\u0437\u0438\u0446\u0438\u044f \u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f.<\/p>\n<pre><code class=\"javascript\">\/\/ \u0443\u0437\u043d\u0430\u0442\u044c \u0442\u0435\u043a\u0443\u0449\u0443\u044e \u043b\u043e\u043a\u0430\u0446\u0438\u044e let id = navigator.geolocation.watchPosition(success, error, options)  \/\/ \u043e\u0447\u0438\u0441\u0442\u043a\u0430 navigator.geolocation.clearWatch(id)<\/code><\/pre>\n<p>\u041c\u0435\u0442\u043e\u0434 watchPosition \u043f\u043e\u0445\u043e\u0436 \u043d\u0430 setTimeout \u0438\u043b\u0438 setInterval, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e \u0432 \u0444\u043e\u043d\u043e\u0432\u043e\u043c \u0440\u0435\u0436\u0438\u043c\u0435 \u0438 \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0435\u0442 \u0442\u0435\u043a\u0443\u0449\u0443\u044e \u043f\u043e\u0437\u0438\u0446\u0438\u044e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. \u0421\u043e\u0445\u0440\u0430\u043d\u044f\u044f \u0435\u0433\u043e \u0432 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439, \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442\u0441\u044f \u0438 \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043d\u0435\u0433\u043e. \u041f\u043e\u0437\u0436\u0435, \u043a\u043e\u0433\u0434\u0430 \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0442\u044c \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f, \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043e\u0447\u0438\u0441\u0442\u0438\u0442\u044c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e \u0438\u043b\u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0435\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043a\u0430\u043a null. \u0415\u0441\u043b\u0438 \u044d\u0442\u043e\u0433\u043e \u043d\u0435 \u0441\u0434\u0435\u043b\u0430\u0442\u044c, \u0432\u0441\u0435 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0432 \u0444\u043e\u043d\u043e\u0432\u043e\u043c \u0440\u0435\u0436\u0438\u043c\u0435, \u0447\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0438\u0432\u0435\u0441\u0442\u0438 \u043a \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430\u043c \u0441 \u043f\u0430\u043c\u044f\u0442\u044c\u044e \u0438 \u043d\u0435\u043d\u0443\u0436\u043d\u043e\u043c\u0443 \u043f\u043e\u0442\u0440\u0435\u0431\u043b\u0435\u043d\u0438\u044e \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432.<\/p>\n<pre><code class=\"javascript\">type GeolocationPosition = {   lat: number   lng: number } type LocationStatus = 'accessed' | 'denied' | 'unknown' | 'error'  export default function Home() {   const [locationStatus, setLocationStatus] = useState&lt;LocationStatus>('unknown')   const [position, setPosition] = useState&lt;GeolocationPosition | null>(null)    useEffect(() => {     let watchId: number | null = null         \/\/ \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0432\u043e\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0442\u044c \u0433\u0435\u043e\u043f\u043e\u0437\u0438\u0446\u0438\u044e \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435     if('geolocation' in navigator) {       watchId = navigator.geolocation.watchPosition((position) => {       setPosition({         lat: position.coords.latitude,         lng: position.coords.longitude       })       setLocationStatus('accessed')       }, (error) => {         switch (error.code) {           case error.PERMISSION_DENIED:             setLocationStatus('denied')             break           case error.POSITION_UNAVAILABLE:             setLocationStatus('unknown')             break           case error.TIMEOUT:             setLocationStatus('error')             break           default:             setLocationStatus('error')             break         }       })       return () => {         if(watchId) {           navigator.geolocation.clearWatch(watchId)         }       }     }   }, []) ... ...<\/code><\/pre>\n<p>\u041f\u0440\u0438 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0435 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b, \u043f\u043e\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044e \u0438 \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043d\u0430 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u041d\u0430 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u0438 \u044d\u0442\u043e\u0433\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f, \u0434\u0430\u043b \u043b\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043d\u0430 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u041a\u0430\u043a \u0442\u043e\u043b\u044c\u043a\u043e \u0433\u0435\u043e\u043b\u043e\u0446\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u043e, \u043f\u043e\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043e\u0431\u044a\u0435\u043a\u0442\u0443 \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f.<\/p>\n<p>\u0421 \u043a\u043e\u0434\u043e\u043c \u043e\u0448\u0438\u0431\u043a\u0438, \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u043c \u0433\u0435\u043e\u043b\u043e\u043a\u0430\u0446\u0438\u0435\u0439, \u043c\u043e\u0436\u043d\u043e \u043b\u0435\u0433\u043a\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043e\u0448\u0438\u0431\u043a\u0443 \u0438 \u0442\u043e\u0447\u043d\u043e \u0443\u0437\u043d\u0430\u0442\u044c, \u043f\u043e\u0447\u0435\u043c\u0443 \u043d\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044e.<\/p>\n<h2>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442 \u043d\u0430 \u043a\u0430\u0440\u0442\u0435<\/h2>\n<p>\u041f\u043e\u043b\u0443\u0447\u0438\u0432 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u0438\u0445 \u0432 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 Map, \u0438 \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u043e \u043d\u0430 \u043a\u0430\u0440\u0442\u0435.<\/p>\n<p>\u041d\u0443\u0436\u043d\u043e, \u0447\u0442\u043e\u0431\u044b \u043c\u0430\u0440\u043a\u0435\u0440 \u043a\u0430\u0440\u0442\u044b \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0430\u043b\u0441\u044f \u043d\u0430 \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u044b\u0435 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u0430\u043c. \u0414\u043b\u044f<\/p>\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-358569","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/358569","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=358569"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/358569\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=358569"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=358569"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=358569"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}