From 8ea1219fe08e02db5bc1e4ba89c17debb9557afc Mon Sep 17 00:00:00 2001 From: zerosoul Date: Wed, 6 Apr 2022 16:29:03 +0800 Subject: [PATCH] refactor: update read index with debounce --- src/common/component/Message/index.js | 50 ++++++++++++--------------- src/routes/chat/ChannelChat/index.js | 23 ++++++++++-- src/routes/chat/DMChat/index.js | 27 +++++++++++---- src/routes/chat/utils.js | 39 +++++++++++++-------- 4 files changed, 86 insertions(+), 53 deletions(-) diff --git a/src/common/component/Message/index.js b/src/common/component/Message/index.js index 6e99e3f6..6bd5990d 100644 --- a/src/common/component/Message/index.js +++ b/src/common/component/Message/index.js @@ -1,40 +1,38 @@ import React, { useRef, useState, useEffect } from "react"; import dayjs from "dayjs"; import { useSelector } from "react-redux"; -import { useInViewRef, useDebounce } from "rooks"; +import { useInViewRef } from "rooks"; import Tippy from "@tippyjs/react"; import Reaction from "./Reaction"; import Reply from "./Reply"; import Profile from "../Profile"; import Avatar from "../Avatar"; -import { useReadMessageMutation } from "../../../app/services/message"; + import StyledWrapper from "./styled"; import Commands from "./Commands"; import EditMessage from "./EditMessage"; import renderContent from "./renderContent"; -function Message({ contextId = 0, mid = "", context = "user" }) { - const [updateReadIndex] = useReadMessageMutation(); - const updateReadDebounced = useDebounce(updateReadIndex, 300); +function Message({ + contextId = 0, + mid = "", + context = "user", + updateReadIndex, + read = true, +}) { const [myRef, inView] = useInViewRef(); const [edit, setEdit] = useState(false); const avatarRef = useRef(null); - const { - footprint, - message = {}, - reactionMessageData, - contactsData, - loginUid, - } = useSelector((store) => { - return { - footprint: store.footprint, - loginUid: store.authData.uid, - reactionMessageData: store.reactionMessage, - message: store.message[mid] || {}, - contactsData: store.contacts.byId, - }; - }); + const { message = {}, reactionMessageData, contactsData } = useSelector( + (store) => { + return { + reactionMessageData: store.reactionMessage, + message: store.message[mid] || {}, + contactsData: store.contacts.byId, + }; + } + ); const toggleEditMessage = () => { setEdit((prev) => !prev); @@ -51,20 +49,16 @@ function Message({ contextId = 0, mid = "", context = "user" }) { edited, properties, } = message; - const readIndex = - context == "user" - ? footprint.readUsers[contextId] - : footprint.readChannels[contextId]; + useEffect(() => { - const read = fromUid == loginUid || mid <= readIndex; - if (inView && !read) { + if (!read) { const data = context == "user" ? { users: [{ uid: +contextId, mid }] } : { groups: [{ gid: +contextId, mid }] }; - updateReadDebounced(data); + updateReadIndex(data); } - }, [mid, readIndex, inView, fromUid, loginUid]); + }, [mid, read]); const reactions = reactionMessageData[mid]; const currUser = contactsData[fromUid] || {}; // if (!message) return null; diff --git a/src/routes/chat/ChannelChat/index.js b/src/routes/chat/ChannelChat/index.js index da85eaee..f31839ec 100644 --- a/src/routes/chat/ChannelChat/index.js +++ b/src/routes/chat/ChannelChat/index.js @@ -1,6 +1,7 @@ import { useState } from "react"; - +import { useDebounce } from "rooks"; import { useSelector } from "react-redux"; +import { useReadMessageMutation } from "../../../app/services/message"; import useChatScroll from "../../../common/hook/useChatScroll"; import ChannelIcon from "../../../common/component/ChannelIcon"; import Send from "../../../common/component/Send"; @@ -21,11 +22,22 @@ import AddMemberModal from "./AddMemberModal"; export default function ChannelChat({ cid = "", dropFiles = [] }) { // const containerRef = useRef(null); + const [updateReadIndex] = useReadMessageMutation(); + const updateReadDebounced = useDebounce(updateReadIndex, 300); const [membersVisible, setMembersVisible] = useState(true); const [addMemberModalVisible, setAddMemberModalVisible] = useState(false); // const dispatch = useDispatch(); - const { msgIds, userIds, data, messageData } = useSelector((store) => { + const { + msgIds, + userIds, + data, + messageData, + loginUid, + footprint, + } = useSelector((store) => { return { + footprint: store.footprint, + loginUid: store.authData.uid, msgIds: store.channelMessage[cid] || [], userIds: store.contacts.ids, data: store.channels.byId[cid] || {}, @@ -45,6 +57,7 @@ export default function ChannelChat({ cid = "", dropFiles = [] }) { const { name, description, is_public, members = [] } = data; const memberIds = members.length == 0 ? userIds : members; console.log("channel message list", msgIds); + const readIndex = footprint.readChannels[cid]; return ( <> {addMemberModalVisible && ( @@ -113,9 +126,13 @@ export default function ChannelChat({ cid = "", dropFiles = [] }) { return Number(a) - Number(b); }) .map((mid, idx) => { - const prev = idx == 0 ? null : messageData[msgIds[idx - 1]]; const curr = messageData[mid]; + if (!curr) return null; + const prev = idx == 0 ? null : messageData[msgIds[idx - 1]]; + const read = curr?.from_uid == loginUid || mid <= readIndex; return renderMessageFragment({ + updateReadIndex: updateReadDebounced, + read, prev, curr, contextId: cid, diff --git a/src/routes/chat/DMChat/index.js b/src/routes/chat/DMChat/index.js index 2ba477e3..6a309724 100644 --- a/src/routes/chat/DMChat/index.js +++ b/src/routes/chat/DMChat/index.js @@ -1,28 +1,38 @@ // import { useState, useEffect } from "react"; import { useSelector } from "react-redux"; +import { useDebounce } from "rooks"; + import addIcon from "../../../assets/icons/add.person.svg?url"; import callIcon from "../../../assets/icons/call.svg?url"; import videoIcon from "../../../assets/icons/video.svg?url"; import useChatScroll from "../../../common/hook/useChatScroll"; import Send from "../../../common/component/Send"; +import { useReadMessageMutation } from "../../../app/services/message"; import Contact from "../../../common/component/Contact"; import Layout from "../Layout"; import { StyledHeader, StyledDMChat } from "./styled"; import { renderMessageFragment } from "../utils"; export default function DMChat({ uid = "", dropFiles = [] }) { + const [updateReadIndex] = useReadMessageMutation(); + const updateReadDebounced = useDebounce(updateReadIndex, 300); console.log("dm files", dropFiles); // const [mids, setMids] = useState([]); - const { msgIds, currUser, messageData } = useSelector((store) => { - return { - currUser: store.contacts.byId[uid], - msgIds: store.userMessage.byId[uid] || [], - messageData: store.message, - }; - }); + const { msgIds, currUser, messageData, footprint, loginUid } = useSelector( + (store) => { + return { + loginUid: store.authData.uid, + footprint: store.footprint, + currUser: store.contacts.byId[uid], + msgIds: store.userMessage.byId[uid] || [], + messageData: store.message, + }; + } + ); const ref = useChatScroll(msgIds); if (!currUser) return null; // console.log("user msgs", msgs); + const readIndex = footprint.readUsers[uid]; return ( { const curr = messageData[mid]; const prev = idx == 0 ? null : messageData[msgIds[idx - 1]]; + const read = curr?.from_uid == loginUid || mid <= readIndex; return renderMessageFragment({ + updateReadIndex: updateReadDebounced, + read, prev, curr, contextId: uid, diff --git a/src/routes/chat/utils.js b/src/routes/chat/utils.js index 0acae950..ca2da2c0 100644 --- a/src/routes/chat/utils.js +++ b/src/routes/chat/utils.js @@ -3,18 +3,18 @@ import dayjs from "dayjs"; import { ContentTypes } from "../../app/config"; import Divider from "../../common/component/Divider"; import Message from "../../common/component/Message"; -function debounce(callback, wait = 2000, immediate = false) { - let timeout = null; - return function () { - const callNow = immediate && !timeout; - const next = () => callback.apply(this, arguments); - clearTimeout(timeout); - timeout = setTimeout(next, wait); - if (callNow) { - next(); - } - }; -} +// function debounce(callback, wait = 2000, immediate = false) { +// let timeout = null; +// return function () { +// const callNow = immediate && !timeout; +// const next = () => callback.apply(this, arguments); +// clearTimeout(timeout); +// timeout = setTimeout(next, wait); +// if (callNow) { +// next(); +// } +// }; +// } export function getUnreadCount({ mids = [], messageData = {}, @@ -22,10 +22,10 @@ export function getUnreadCount({ readIndex = 0, }) { console.log({ mids, loginUid, readIndex }); - // 先过滤掉from自己的 + // 先过滤掉空信息和from自己的 const others = mids.filter((mid) => { const { from_uid = 0 } = messageData[mid] || {}; - return from_uid != loginUid; + return messageData[mid] && from_uid != loginUid; }); if (others.length == 0) return 0; if (readIndex == 0) return others.length; @@ -71,6 +71,8 @@ export const renderPreviewMessage = (message = null) => { return res; }; export const renderMessageFragment = ({ + read = true, + updateReadIndex, prev = null, curr = null, contextId = 0, @@ -92,7 +94,14 @@ export const renderMessageFragment = ({ return ( {divider && } - + ); };