You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native 对接 Django Channels 如何正确创建管理 WebSocket 避免问题

React Native + Django Channels WebSocket连接问题解决方案

问题根因

  • TypeError: chatSocket.close is not a function报错是因为闭包陷阱:useEffect中捕获的chatSocket是初始值(空对象),setSocket更新state是异步的,触发beforeRemove事件时拿到的仍然是初始的空对象,没有close方法。
  • 旧连接未关闭是因为useEffect没有配置正确的依赖项和清理函数,切换房间/退出页面时不会主动销毁旧连接实例。
  • 重渲染重复创建连接是因为直接在组件顶层初始化WebSocket,每一次组件重渲染都会执行构造函数新建连接。

正确实现方案

推荐用useRef存储WebSocket实例,比useState更适合:useRef的current属性是可变的,不会触发组件重渲染,也不存在state更新的异步和闭包问题。

前端代码示例

import {useRef, useState, useEffect} from 'react';

const ChatScreen = ({navigation, route}) => {
  const room = route.params.item;
  // 用ref存储socket实例
  const chatSocketRef = useRef(null);
  const [chat, setChat] = useState([]);
  const [message, setMessage] = useState('');

  const getMsgs = () => {
    apiServer.get(`/chat/api/rooms/${room.id}`)
      .then((resp) => setChat(resp.data))
      .catch((e) => console.log(e));
  };

  const sendMsg = () => {
    // 发送前先判断连接状态,避免报错
    if (chatSocketRef.current?.readyState === WebSocket.OPEN) {
      chatSocketRef.current.send(JSON.stringify({
        message,
        room: room.id,
        owner: 1
      }));
    }
  };

  useEffect(() => {
    // 初始化新连接
    const socket = new WebSocket(`ws://192.168.1.14:8000/ws/chat/${room.name}/`);
    chatSocketRef.current = socket;

    // 绑定事件监听
    socket.onmessage = () => getMsgs();
    socket.onerror = (e) => console.log('WebSocket错误:', e);
    socket.onclose = (e) => console.log('连接关闭:', e.code, e.reason);

    // 路由离开前关闭连接
    const beforeRemoveListener = navigation.addListener('beforeRemove', () => {
      if (chatSocketRef.current?.readyState === WebSocket.OPEN) {
        chatSocketRef.current.close(1000, '用户主动离开房间');
      }
      chatSocketRef.current = null;
    });

    // 清理函数:组件卸载、切换房间时自动销毁旧连接
    return () => {
      beforeRemoveListener();
      if (chatSocketRef.current?.readyState === WebSocket.OPEN) {
        chatSocketRef.current.close(1000, '组件卸载/切换房间');
      }
      chatSocketRef.current = null;
    };
  // 依赖加入room.name,切换房间时自动重建连接
  }, [navigation, room.name]);

  return (
    <TouchableOpacity 
      onPress={() => {
        sendMsg();
        setMessage('');
      }}
    >
      发送消息
    </TouchableOpacity>
  )
}

后端注意事项

你现有ChatConsumer的disconnect逻辑是正确的,会自动将连接从房间组中移除,不会出现关闭连接后仍然收到消息的问题,只需要按需添加日志排查连接关闭情况即可。

可选优化

如果你的应用需要后台保活WebSocket,不需要每次退出房间就关闭连接,可以将socket实例提到全局状态(比如Context、Redux)中管理,只在用户登出、网络切换时重建/关闭连接,减少连接重建的开销。

内容的提问来源于stack exchange,提问作者Hazem gamal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 02:48:03