【问题标题】:Can't perform a React state update on an unmounted component. useEffect React-Native无法对未安装的组件执行 React 状态更新。 useEffect React-Native
【发布时间】:2022-01-18 02:49:13
【问题描述】:

我正在使用 react-native、node、mongoose、socket.io 开发一个聊天应用程序,问题是,当使用 socket.io 时,当我从 user1 向 user2 发送消息时,我能够接收到发送的消息来自 user1 的消息,但 useEffect 不会重新渲染组件以将新消息添加到 messages 的数组中,即使我输入了正确的依赖项。下面是代码供参考:

这是我的 MessageScreen,我在功能组件 MessageScreen 的范围之外定义了 socket

const socket = io('ws://192.168.29.123:8080', {
    transports: ['websocket'],
}); // declared outside the functional component

const [arrivalMessage, setArrivalMessage] = useState(null);

    useEffect(() => {
        socket.on('getMessage', data => {
            console.log('received: ',data);
            setArrivalMessage({
                matchId: matchId,
                senderId: data.senderId,
                text: data.text,
                createdAt: Date.now(),
                updatedAt: Date.now(),
            });
        });
        console.log('arrival msg: ',arrivalMessage);
    // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [arrivalMessage, socket]);

    useEffect(() => {
        // ensures we don't get anyother user's msg
        arrivalMessage &&
        match.includes(arrivalMessage.senderId) &&
        setMessages((prev) => [...prev, arrivalMessage]);
    }, [arrivalMessage, match]);

    useEffect(() => {
        socket.emit('addUser', uid);
    }, [uid]);

虽然我从朋友那里收到了正确的数据,但状态没有更新,因此我无法显示实时消息。 因此,每当我从 1 个用户向另一个用户发送消息时,这就是我的控制台输出,它确认我能够从该用户接收消息并且显然是标题错误:

LOG  received:  {"senderId": "61b5d1725a7ae2994", "text": {"matchId":"61b5d172511867ae298c", "senderId": "61b5d1725a7ae2994", "text": "me too!"}}
ERROR  Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function. in MessageScreen (at SceneView.tsx:126)
LOG  received:  {"senderId": "61b5d1725a7ae2994", "text":{"matchId":"61b5d111867ae298c","senderId":"61b5d1725a7ae2994", "text": "me too!"}}

如果有人能指出这里有什么问题,那将非常有帮助! 谢谢!

【问题讨论】:

    标签: javascript reactjs react-native socket.io


    【解决方案1】:

    组件卸载时需要关闭socket监听

     useEffect(() => {
            const callback = data => {
                console.log('received: ',data);
                setArrivalMessage({
                    matchId: matchId,
                    senderId: data.senderId,
                    text: data.text,
                    createdAt: Date.now(),
                    updatedAt: Date.now(),
                })
            }
        
            socket.on('getMessage', callback);
            console.log('arrival msg: ',arrivalMessage);
    
            // ADD THIS
            return () => {
              socket.off(event, callback)
            }
        
        // eslint-disable-next-line react-hooks/exhaustive-deps
        }, [arrivalMessage, socket]);
    

    如果没有必要,您也不希望套接字运行。我不会从组件中启动套接字,它可能会留在内存中并导致内存泄漏。

    更好的方法是创建一个上下文,您可以在其中启动套接字并包装需要它的应用程序/组件。如果您的组件卸载,套接字将断开连接。

    import SocketClient from 'socket.io-client'
    
    export function useSocket(url) {
      const [socket, setSocket] = useState(null)
    
      useEffect(() => {
        const io = SocketClient(url).connect()
        setSocket(io)
    
        return () => {
          socket?.disconnect()
        }
    
        // eslint-disable-next-line react-hooks/exhaustive-deps
      }, [])
    
      return socket
    }
    
    const SocketsContext = createContext({
      socket: undefined,
    })
    
    function SocketsContextProvider({ children }) {
      const socket = useSocket()
    
      return (
        <SocketsContext.Provider value={{ socket }}>
          {children}
        </SocketsContext.Provider>
      )
    }
    
    export function useSocketEvent(event, callback) {
      const { socket } = useContext(SocketsContext)
    
      useEffect(() => {
        if (!socket) {
          return
        }
    
        socket.on(event, callback)
    
        return () => {
          socket.off(event, callback)
        }
      }, [callback, event, socket])
    
      return socket
    }
    
    function ParentComponentWithSockets(){
      return (
        <SocketsContextProvider>
          <YourComponent />
        </SocketsContextProvider>
      )
    }
    
    function YourComponent(){
      const [arrivalMessage, setArrivalMessage] = useState(null);
    
      useSocketEvent('getMessage', data => {
        setArrivalMessage({
           matchId: matchId,
           senderId: data.senderId,
           text: data.text,
           createdAt: Date.now(),
           updatedAt: Date.now(),
        })
      })
    
      return (
       //...
      )
    }
    

    【讨论】:

    • 像魅力一样工作!非常感谢!
    • 很高兴我能帮上忙 :)
    猜你喜欢
    • 1970-01-01
    • 2021-11-30
    • 2020-09-03
    • 2019-07-24
    • 1970-01-01
    • 2021-12-03
    • 2019-09-11
    • 2021-08-07
    • 2020-06-14
    相关资源
    最近更新 更多