Задать вопрос
@X-yro

Почему вебсокет постоянно в состоянии подключения при вызове send?

Всех приветствую. Решил написать веб чат на Django&Channels, React&Websocket. Я успешно подключаюсь к сокету и отключаюсь от него, то есть при входе и выходе из комнаты нет проблем, так вот к сути проблемы когда я захожу в комнату происходит подключение, отправляю сообщение, оно принимается бэком и возвращается, выхожу из комнаты, соединение соответственно разрывается и при повторном заходе в ту же комнату или любую другую ловлю такую ошибку

Failed to execute 'send' on 'WebSocket': Still in CONNECTING state.


Room.jsx

import React, { useEffect, useRef, useState } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import '../App.css'
import Container from 'react-bootstrap/Container';
import Row from 'react-bootstrap/Row';
// import Col from 'react-bootstrap/Col';
import Button from 'react-bootstrap/Button';
import { ServerMessage } from '../Redux-apps/RdxContext';



const Room = () => {
  const name = useSelector(state => state.nameOfRoom.value)

  const dispatch = useDispatch()
  const message = useSelector(state => state.messageFromServer.message)

  const [text, setText] = useState('')
  const [fromBack, setFromBack] = useState('')

  const socketRef = useRef(null)

  const formOnSubmit = (elem) => {
    elem.preventDefault()
    elem.target.reset()
    dispatch(ServerMessage(text))

  }




  useEffect(() => {
    if (name.length > 0) {
      // Создаем объект WebSocket только один раз
      socketRef.current = new WebSocket(`ws://127.0.0.1:8000/ws/room/${name}/`)
      socketRef.current.onopen = () => {
        console.log('Подключение установлено')
      }
      socketRef.current.onclose = () => console.log('Подключение разорвано')
      socketRef.current.onmessage = (msg) => {
        let data = JSON.parse(msg.data)
        console.log(data.type)
        setFromBack(data.message)
      }
    }
    console.log(socketRef.current.readyState)
    // Закрываем соединение при размонтировании компонента
    return () => {
      if (socketRef.current) {
        socketRef.current.close()
      }
    }
  }, [name])

  useEffect(() => {
    if (socketRef.current && message) {
      socketRef.current.send(
        JSON.stringify({
          'message': message    
        })
      )
    }
  })



  console.log(fromBack)
  return (
    <Container>
      <Row>
        <div className='mt-5'>
          <div className='chat-window'>
            <div className="message-blue">
              <p className="message-content">{fromBack}</p>
            </div>
          </div>
          <div>
            <form onSubmit={formOnSubmit}>
              <input
                onChange={(e) => setText(e.target.value)}
                className='chat-input mt-5'
                type="text"
              />

              <Button type='submit' variant="outline-secondary" id="button-addon2">Button</Button>
            </form>
          </div>
        </div>
      </Row>
    </Container>
  )
}

export default Room


consumer.py

import json

from asgiref.sync import sync_to_async
from channels.generic.websocket import AsyncWebsocketConsumer
from channels.db import database_sync_to_async
from django.forms.models import model_to_dict

from .models import Message, Room


class ChatConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        self.room_name = self.scope['url_route']['kwargs']['room_name']
        self.room_group_name = f'chat_{self.room_name}'
        self.create_room = await database_sync_to_async(Room.objects.get_or_create)(slug=self.room_name)

        print(f'Путь до комнаты: {self.scope["path"]}')
        await self.channel_layer.group_add(
            self.room_group_name,
            self.channel_name
        )

        await self.accept()
        # await self.send(json.dumps('sucessfully connected!'))

    async def disconnect(self, close_code):
        await self.channel_layer.group_discard(
            self.room_group_name,
            self.channel_name
        )

    @database_sync_to_async
    def get_messages(self):
        messages = Message.objects.filter(room__room=self.room_name)
        msg = []
        for m in messages:
            msg.append(m)
        return msg

    @database_sync_to_async
    def create_message(self, message, room):
        return Message.objects.create(message=message, room=room)

    @database_sync_to_async
    def get_room(self):
        return Room.objects.get(slug=self.room_name)

    async def receive(self, text_data=None, bytes_data=None):
        data = json.loads(text_data)
        message = data['message']
        room = await self.get_room()
        save_message = await self.create_message(message, room=room)
        print(f'Receive: {message}')

        await self.channel_layer.group_send(
            self.room_group_name,
            {
                'type': 'chat_message',
                'message': message
            }
        )

    async def chat_message(self, event):
        message = event['message']
        print(f'Send: {message}')

        await self.send(text_data=json.dumps(
            {
                'message': message
            }
        ))


в consumer.py есть не используемые вещи связанные с получением и передачей данных из бд, на них можете не обращать внимание.
  • Вопрос задан
  • 130 просмотров
Подписаться 1 Средний 7 комментариев
Решения вопроса 1
Kentavr16
@Kentavr16
long cold winter
попробуй
if(socketRef.current && socketRef.current.readyState === 1 && message)


Много с сокетами в реакте не работал, но мне кажется что это плохой код. Компонент может ререндериться несколько раз, и сокет будет дергать на каждом ререндере. Хотя бы добавить проверку в первом эффекте что реф пустой.
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы