代码之家  ›  专栏  ›  技术社区  ›  bobby boy

试图弄清楚如何使用套接字。io在useEffect中的正确方式是使用axios get请求获取消息

  •  0
  • bobby boy  · 技术社区  · 2 年前

    我使用的所有信息都会对当前状态产生影响。从现在起,直到页面刷新,它才呈现新状态。

    const Home = ({ user, logout }) => {
      const history = useHistory();
    
      const socket = useContext(SocketContext);
    
      const [conversations, setConversations] = useState([]);
      const [activeConversation, setActiveConversation] = useState(null);
    
      const classes = useStyles();
      const [isLoggedIn, setIsLoggedIn] = useState(false);
    
      const addSearchedUsers = (users) => {
        const currentUsers = {};
    
        // make table of current users so we can lookup faster
        conversations.forEach((convo) => {
          currentUsers[convo.otherUser.id] = true;
        });
    
        const newState = [...conversations];
        users.forEach((user) => {
          // only create a fake convo if we don't already have a convo with this user
          if (!currentUsers[user.id]) {
            let fakeConvo = { otherUser: user, messages: [] };
            newState.push(fakeConvo);
          }
        });
    
        setConversations(newState);
      };
    
      const clearSearchedUsers = () => {
        setConversations((prev) => prev.filter((convo) => convo.id));
      };
    
      const saveMessage = async (body) => {
        const { data } = await axios.post("/api/messages", body);
        return data;
      };
    
      const sendMessage = (data, body) => {
        socket.emit("new-message", {
          message: data.message,
          recipientId: body.recipientId,
          sender: data.sender,
        });
      };
    
      const postMessage = async (body) => {
        try {
          const data = await saveMessage(body);
    
          if (!body.conversationId) {
            addNewConvo(body.recipientId, data.message);
          } else {
            addMessageToConversation(data);
          }
          sendMessage(data, body);
        } catch (error) {
          console.error(error);
        }
      };
      const addNewConvo = useCallback(
        (recipientId, message) => {
          conversations.forEach((convo) => {
            if (convo.otherUser.id === recipientId) {
              convo.messages.push(message);
              convo.latestMessageText = message.text;
              convo.id = message.conversationId;
            }
          });
          setConversations(conversations);
        },
        [setConversations, conversations],
      );
    
      const addMessageToConversation = useCallback(
        (data) => {
          // if sender isn't null, that means the message needs to be put in a brand new convo
          const { message, sender = null } = data;
          if (sender !== null) {
            const newConvo = {
              id: message.conversationId,
              otherUser: sender,
              messages: [message],
            };
            newConvo.latestMessageText = message.text;
            setConversations((prev) => [newConvo, ...prev]);
          }
          conversations.forEach((convo) => {
            console.log('hi', message.conversationId)
            if (convo.id === message.conversationId) {
              const convoCopy = { ...convo }
              convoCopy.messages.push(message);
              convoCopy.latestMessageText = message.text;
              console.log('convo', convoCopy)
    
            } else {
              return convo
            }
          });
          setConversations(conversations);
        },
        [setConversations, conversations],
      );
    
      const setActiveChat = useCallback((username) => {
        setActiveConversation(username);
      }, []);
    
      const addOnlineUser = useCallback((id) => {
        setConversations((prev) =>
          prev.map((convo) => {
            if (convo.otherUser.id === id) {
              const convoCopy = { ...convo };
              convoCopy.otherUser = { ...convoCopy.otherUser, online: true };
              return convoCopy;
            } else {
              return convo;
            }
          }),
        );
      }, []);
    
      const removeOfflineUser = useCallback((id) => {
        setConversations((prev) =>
          prev.map((convo) => {
            if (convo.otherUser.id === id) {
              const convoCopy = { ...convo };
              convoCopy.otherUser = { ...convoCopy.otherUser, online: false };
              return convoCopy;
            } else {
              return convo;
            }
          }),
        );
      }, []);
    
      // Lifecycle
    
      useEffect(() => {
        // Socket init
        socket.on("add-online-user", addOnlineUser);
        socket.on("remove-offline-user", removeOfflineUser);
        socket.on("new-message", addMessageToConversation);
    
        return () => {
          // before the component is destroyed
          // unbind all event handlers used in this component
          socket.off("add-online-user", addOnlineUser);
          socket.off("remove-offline-user", removeOfflineUser);
          socket.off("new-message", addMessageToConversation);
        };
      }, [addMessageToConversation, addOnlineUser, removeOfflineUser, socket]);
    
      useEffect(() => {
        // when fetching, prevent redirect
        if (user?.isFetching) return;
    
        if (user && user.id) {
          setIsLoggedIn(true);
        } else {
          // If we were previously logged in, redirect to login instead of register
          if (isLoggedIn) history.push("/login");
          else history.push("/register");
        }
      }, [user, history, isLoggedIn]);
    
      useEffect(() => {
        const fetchConversations = async () => {
          try {
            const { data } = await axios.get("/api/conversations");
            setConversations(data);
          } catch (error) {
            console.error(error);
          }
        };
        if (!user.isFetching) {
          fetchConversations();
        }
      }, [user]);
    
      const handleLogout = async () => {
        if (user && user.id) {
          await logout(user.id);
        }
      };
    
      return (
        <>
          <Button onClick={handleLogout}>Logout</Button>
          <Grid container component="main" className={classes.root}>
            <CssBaseline />
            <SidebarContainer
              conversations={conversations}
              user={user}
              clearSearchedUsers={clearSearchedUsers}
              addSearchedUsers={addSearchedUsers}
              setActiveChat={setActiveChat}
            />
            <ActiveChat
              activeConversation={activeConversation}
              conversations={conversations}
              user={user}
              postMessage={postMessage}
            />
          </Grid>
        </>
      );
    };
    这是我工作的主要部分,当我开始这个项目时,它有启动代码,并且被告知不要触摸后端,所以我知道前端代码有问题。我觉得我错过了一些重要的东西。木卫一

    import { io } from 'socket.io-client';
    
    import React from 'react';
    
    
    export const socket = io(window.location.origin);
    socket.on('connect', () => {
      console.log('connected to server');
    });
    
    export const SocketContext = React.createContext();

    这就是我的插座。io设置,如果有人能给我指出正确的方向,那就太酷了。我一直在阅读有关插座的资料。我尽我所能,但我还是很迷茫。

    1 回复  |  直到 2 年前
        1
  •  0
  •   Bas    2 年前

    基于后端正常工作的假设。。。

      const addNewConvo = useCallback(
        (recipientId, message) => {
          conversations.forEach((convo) => {
            if (convo.otherUser.id === recipientId) {
              convo.messages.push(message);
              convo.latestMessageText = message.text;
              convo.id = message.conversationId;
            }
          });
          setConversations(conversations);
        },
        [setConversations, conversations],
      );
    

    setConversations(conversations);

    这是一种使用状态变量设置状态的错误方法,因此它不会做任何事情。很可能是你的代码在刷新之前不会更改的原因。

    建议的解决方案:

      const addNewConvo = useCallback(
        (recipientId, message) => {
            setConversations(previousState => previousState.map(convo => {
            if (convo.otherUser.id === recipientId) {
                convo.messages.push(message)
                convo.latestMessageText = message.text;
                convo.id = message.conversationId;
                return convo
            }
            return convo
          }))
        },
        [setConversations, conversations],
      );
    

    注意:由于我对邮件进行了深度复制,因此上述工作可以更有效地完成