• 【招聘App】—— React/Nodejs/MongoDB全栈项目:消息列表


    前言:最近在学习Redux+react+Router+Nodejs全栈开发高级课程,这里对实践过程作个记录,方便自己和大家翻阅。最终成果github地址:https://github.com/66Web/react-antd-zhaoping,欢迎star。


    一、聊天信息根据用户分组

    • 从redux中获取到chatmsg:其中包含了所有与当前用户有关的聊天信息
    • 不同的用户聊天信息的chatid不同:根据chatid可将数据分到不同的数组
      //按照聊天用户分组,根据 chatid
      const msgGroup = {}
      this.props.chat.chatmsg.forEach(v=>{
           msgGroup[v.chatid] = msgGroup[v.chatid] || []
           msgGroup[v.chatid].push(v)
      })
    • Object.values()返回数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键名

    • 将分好组的聊天信息,通过Object.values()获得新的二维数组

      const chatList = Object.values(msgGroup)  

    二、聊天列表展示

    • 获取【最后一条聊天信息】
    1. 定义一个方法返回数组的最后一个值:每个用户的聊天信息自动按照create_time排序,最后即最新
      getLast = (arr) => {
           return arr[arr.length-1]
      }
    2. 遍历用户信息二维数组,获得每一个用户的聊天信息数组,调用方法获取最后一条信息

      {chatList.map(v=>{
              // console.log(v)
              const lastItem = this.getLast(v)   
    • 获取【对方用户】的用户名及头像
    1. 从redux中获取到当前用户的userid,以及存储所有用户name和avatar的userinfo
    2. 遍历获得每一个用户的聊天信息数组后,判断聊天信息的from是否为当前userid,如果是则将to赋给targetId,否则赋from
      const Item = List.Item
      const Brief = Item.Brief
      const userid = this.props.user._id
      const userinfo = this.props.chat.users
      
      //其它代码
      const targetId = v[0].from==userid?v[0].to:v[0].from
      return (
            <List key={lastItem._id}>
                   <Item
                           thumb={require(`../img/${userinfo[targetId].avatar}.png`)}
                           arrow="horizontal"
                           onClick={()=>{
                                    this.props.history.push(`/chat/${targetId}`)
                           }}
                   >
                      {lastItem.content}
                      <Brief>{userinfo[targetId].name}</Brief>
                   </Item>
             </List>
      )
      
    • 获取【未读消息数】:过滤显示read为false,且to时当前用户userid的聊天信息数组的length数

      const unreadNum = v.filter(v=>!v.read&&v.to==userid).length
      
      extra={<Badge text={unreadNum}></Badge>}
      

        

    三、最新消息排序

    • 给二维数组进行排序:比较不同用户聊天信息的最后一条的create_time,最大者最新,优先显示
      //用户信息数组的数组、排序
      const chatList = Object.values(msgGroup).sort((a, b)=>{
            const a_last = this.getLast(a).create_time
            const b_last = this.getLast(b).create_time
            return b_last - a_last
      })
      

        

    四、消息未读数更新

    • 获取当前聊天的目标用户【to】,发送给后端更新数据库中的未读消息
    1. chat.js中:为了在当前打开的聊天页面中【伪同步】标识消息已读,在componentWillUnmount时更新消息
      componentWillUnmount(){
           const to = this.props.match.params.user
           this.props.readMsg(to)
      }  
    2. chat.redux.js中:定义readMsg(from),通过axios.post发送请求,将目标用户的userid【to】传给后端(更新条件:聊天信息中只有from为【to】,即目标用户发来的才算未读

      //操作数据的方法
      export function readMsg(from){
          return (dispatch, getState)=>{
              axios.post('/user/readmsg',{from})
                  .then(res=>{
                      console.log(res)
                  })
          }
      }
      
    • user.js中:处理标识已读的后端请求/readmsg,更新数据库中的聊天信息

    1. 更新条件一:聊天信息的to为当前用户的userid,从req.cookies中获取到

    2. 更新条件二:聊天信息的from为目标用户的userid,从req.body中获取到

    3. 满足条件时:将聊天信息的read字段,设置为true,标识已读

    4. mongodb的更新操作默认只更新第一条,设置{'multi':true}可同时更新多条

    5. 更新成功后:返回更新成功的数据条数doc.nModified

      //标识已读
      Router.post('/readmsg', function(req, res){
          const userid = req.cookies.userid
          const {from} = req.body
          console.log(userid, from)
          Chat.update({from, to:userid}, 
                      {'$set':{read:true}}, 
                      {'multi':true},function(err, doc){
              if(!err){
                  return res.json({code:0, num:doc.nModified})
              }
              return res.json({code:1, msg:'修改失败'})
          })
      })
      

    • chat.redux.js中:将数据库中标识已读之后的聊天信息数据存入redux中

      //action type
      const MSG_READ = 'MSG_READ'  //标识已读
      
      //reducer中:只标识当前用户与目标用户的聊天信息中from为目标用户的信息
       case MSG_READ:
              const {from, num} = action.payload
              return {...state, chatmsg:state.chatmsg.map(v=>({...v, read:from==v.from?true:v.read})) , unread:state.unread-num}
      
      //action creator
      function msgRead({from, to, num}){
          return {type:MSG_READ, payload:{from, to, num}}
      }
      
      //readMsg方法中:成功获取后端返回的数据后,触发action将数据存入redux
      axios.post('/user/readmsg',{from})
            .then(res=>{
                  const userid = getState().user._id
                  if(res.status==200&&res.data.code==0){
                        dispatch(msgRead({userid, from, num:res.data.num}))
                  }
      })

    注:项目来自慕课网

  • 相关阅读:
    代理模式和策略模式的区别
    代理模式vs适配器模式vs外观模式 转
    装饰模式与代理模式的区别(转载)
    用Delphi实现动态代理(2):设计说明  转
    Java静态内部类的介绍
    非常好的Java反射例子
    Java多线程中的锁机制
    Java多线程共享数据、同步、通信
    Java程序运行超时后退出解决
    Java安全:运用加密技术保护Java源代码
  • 原文地址:https://www.cnblogs.com/ljq66/p/10295587.html
Copyright © 2020-2023  润新知