Last active
          October 26, 2025 21:14 
        
      - 
      
- 
        Save sunmeat/de9253cc22e3fc96ff0a2527c3bd10a9 to your computer and use it in GitHub Desktop. 
    useEffect з підпискою на Websocket, оновленням тайтла та логуванням
  
        
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | App.jsx: | |
| import { useState, useEffect, useRef } from 'react'; | |
| import './App.css'; | |
| function App() { | |
| const [messages, setMessages] = useState([]); | |
| const [unreadCount, setUnreadCount] = useState(0); | |
| const [log, setLog] = useState([]); | |
| const ws = useRef(null); | |
| const msgId = useRef(1); | |
| // підключення до WebSocket і підписка на вхідні повідомлення | |
| useEffect(() => { | |
| ws.current = new WebSocket('wss://ws.postman-echo.com/raw'); | |
| // wss://ws.postman-echo.com/raw — це публічний WebSocket ехо-сервер, наданий Postman, популярним інструментом для тестування API | |
| // що робить цей сервіс: | |
| // 1) приймає WebSocket-повідомлення від клієнта | |
| // 2) миттєво надсилає назад (echo) ті самі повідомлення | |
| // 3) використовується виключно для тестування — не зберігає стан, не маршрутизує повідомлення іншим клієнтам, не підтримує повноцінний чат тощо | |
| // https://blog.postman.com/introducing-postman-websocket-echo-service/ | |
| // альтернативи: Socket.IO, PieSocket Demo, WebSocket.org Echo, SocketBay, Mocksocket by Mocky, WebSocket-сервера на Fastify / Express / NestJS, PubNub, Ably, Pusher, власний сервер :) | |
| // https:// — це HTTP, і можна робити ТІЛЬКИ односпрямовані запити (клієнт → сервер, сервер відповідає) | |
| // wss:// — це WebSocket, і він дозволяє двосторонню зв’язок: сервер може сам надсилати дані клієнту в будь-який час, не чекаючи запиту! | |
| // https://datatracker.ietf.org/doc/html/rfc6455 | |
| ws.current.onopen = () => { | |
| console.log('WebSocket відкрито'); | |
| // надсилаємо повідомлення кожні 2 секунди | |
| ws.current.sendInterval = setInterval(() => { | |
| const message = `Повідомлення #${msgId.current}`; | |
| ws.current.send(message); | |
| msgId.current += 1; | |
| }, 2000); | |
| }; | |
| ws.current.onmessage = (event) => { | |
| const received = event.data; | |
| setMessages(prev => [...prev, received]); | |
| setUnreadCount(prev => prev + 1); | |
| }; | |
| ws.current.onerror = (err) => { | |
| console.error('WebSocket помилка:', err); | |
| }; | |
| ws.current.onclose = () => { | |
| console.log('WebSocket закрито'); | |
| clearInterval(ws.current.sendInterval); | |
| }; | |
| // очищення | |
| return () => { | |
| if (ws.current) { | |
| clearInterval(ws.current.sendInterval); | |
| ws.current.close(); | |
| } | |
| }; | |
| }, []); | |
| // оновлення document.title при отриманні нових повідомлень | |
| useEffect(() => { | |
| document.title = unreadCount > 0 | |
| ? `(${unreadCount}) Нові повідомлення` | |
| : 'Немає нових повідомлень'; | |
| }, [unreadCount]); | |
| // логування повідомлень (аналіз дій) | |
| useEffect(() => { | |
| if (messages.length > 0) { | |
| const latest = messages[messages.length - 1]; | |
| const entry = `[${new Date().toLocaleTimeString('uk-UA')}] Отримано: ${latest}`; | |
| setLog(prev => [...prev, entry]); | |
| } | |
| }, [messages]); | |
| return ( | |
| <div> | |
| <h1>Панель WebSocket</h1> | |
| <p><strong>Останнє повідомлення:</strong> {messages[messages.length - 1] || '—'}</p> | |
| <p><strong>Непрочитані:</strong> {unreadCount}</p> | |
| <button onClick={() => setUnreadCount(0)}>Очистити лічильник</button> | |
| <h2>Повідомлення:</h2> | |
| <ul> | |
| {messages.map((msg, i) => ( | |
| <li key={i}>{msg}</li> | |
| ))} | |
| </ul> | |
| <h2>Лог подій:</h2> | |
| <ul> | |
| {log.map((entry, i) => ( | |
| <li key={i}>{entry}</li> | |
| ))} | |
| </ul> | |
| </div> | |
| ); | |
| } | |
| export default App; | |
| ========================================================================================================== | |
| App.css: | |
| body { | |
| margin: 0; | |
| padding: 0; | |
| background: linear-gradient(to right, #0f0f0f, #1a1a1a); | |
| color: #e0e0e0; | |
| font-family: 'Courier New', monospace; | |
| font-size: 16px; | |
| line-height: 1.6; | |
| overflow-x: hidden; | |
| } | |
| h1, h2 { | |
| color: #00fff7; | |
| text-shadow: 0 0 10px #00fff7; | |
| margin-bottom: 10px; | |
| } | |
| div { | |
| max-width: 900px; | |
| margin: 50px auto; | |
| padding: 40px; | |
| background: rgba(30, 30, 30, 0.95); | |
| border-radius: 16px; | |
| box-shadow: 0 0 30px rgba(0, 255, 255, 0.3); | |
| } | |
| strong { | |
| color: #ffd700; | |
| } | |
| p { | |
| margin: 12px 0; | |
| } | |
| button { | |
| background: linear-gradient(to right, #ff004c, #ff6e00); | |
| color: white; | |
| border: none; | |
| padding: 10px 20px; | |
| font-weight: bold; | |
| border-radius: 12px; | |
| cursor: pointer; | |
| transition: background 0.3s ease, transform 0.1s ease; | |
| margin-bottom: 20px; | |
| } | |
| button:hover { | |
| background: linear-gradient(to right, #ff6e00, #ff004c); | |
| transform: scale(1.05); | |
| box-shadow: 0 0 12px #ff004c; | |
| } | |
| ul { | |
| list-style: none; | |
| padding-left: 0; | |
| margin-top: 10px; | |
| max-height: 200px; | |
| overflow-y: auto; | |
| background: rgba(255, 255, 255, 0.05); | |
| border-radius: 12px; | |
| padding: 15px; | |
| } | |
| li { | |
| margin-bottom: 8px; | |
| padding: 6px 10px; | |
| background: rgba(255, 255, 255, 0.08); | |
| border-left: 4px solid #00fff7; | |
| border-radius: 6px; | |
| transition: background 0.2s ease; | |
| } | |
| li:hover { | |
| background: rgba(255, 255, 255, 0.15); | |
| } | 
  
    Sign up for free
    to join this conversation on GitHub.
    Already have an account?
    Sign in to comment