美文网首页
项目详细说明

项目详细说明

作者: 谷子多 | 来源:发表于2018-07-12 03:09 被阅读0次
  setTimeout(function(){
            window.dispatchEvent(new Event('resize'))
        },0)

问:为什么这个项目需要redux:

做项目的时候我通过不停总结,总算想通了:
每次在页面发生跳转的时候,为了确保在下一次渲染正确的页面(每个发生跳转的页面内部都获取了redux的state,通过redirect字段来判断跳转),就必须更改redux的数据。
还有其他的内容渲染也依赖最新redux数据!!所以你必须时时刻刻及时改变redux的数据!


一、项目学习过程中的几点总结:

1、登录注册的关键点 :
redux里建立登录注册两个方法,通过该方法比较自身state和后台请求的数据是否相同(在组件内部调用该方法,参数是组件自己的sate),如验证通过,改变redux的state
比如:genius/boss页面,底部icon是渲染boss还是genius,就是取决于state里的type字段。
2、请求数据的组件:
登录、注册(提交后台用户名、密码、身份)、完善信息(提交后台头像,描述等等)
3、cookie :
添加登录成功,后台设置cookie保存登录状态;2、写cookie是在登录后,读cookie在用户请求时,先读一下是否有cookie,
所以刷新页面会停留在上次的页面,正是因为cookie设置的原因**。
4、关于Ant Design
该组件库没有实现和react-router-dom的切换路由的良好配合,所以平时我们是通过Link标签切换路由,而引用这个组件库的navbar时直接用this.props.history里push吧!


二、页面逻辑讲解:

页面跳转 :

为什么每次跳转都正确的渲染了页面?
redux的state设置了redirect,传入一个跳转方法。

详解过程:在请求数据后,会在action里传入请求到的data,在redux的state里设置redirect(跳转字段),该字段接收一个页面跳转方法,参数为请求到的数据,该跳转方法的内部逻辑就是解耦请求到的data,获取type,通过该字段决定跳转到对应的页面(boss/genius,bossinfo/geniusinfo)。

发生跳转的几个组件:

  1. 登录:完成提交了AUTH_SUCESS,改变了state的redirect,发生了跳转
  2. 注册:提交了AUTH_SUCESS,改变了state的redirect,发生了跳转
  3. 完善信息:提交了AUTH_SUCESS,改变了state的redirect,发生了跳转
    共同点:改变state,为redirectTo的绑定跳转函数,组件内部设置Redirect重定向组件,所以:正确的渲染了对应的页面。
 case AUTH_SUCESS:
            return {...state,msg:'',redirectTo:getRedirectPath(action.data),...action.data,pwd:''}

export function getRedirectPath({type, avatar}){
    // 根据用户信息 返回跳转地址
    // user.type /boss /genius
    // user.avatar /bossinfo /geniusinfo 
    console.log(type)
    let url = (type==='boss')?'/boss': '/genius'
    if (!avatar) {
        url += 'info'
    }
    
    return url
}

要在各组件内放置:

{this.props.redirectTo?<Redirect to="this.props.redirectTo"/>:null}

登录:

要做的事

  • 请求数据
  • 将请求到的数据合并到redux的state
  • 跳转页面。
    组件内代码讲解:设置自己的state(字段:user,pwd),在表单控件发生变化的同时setstate,点击登录按钮时传入redux的校验方法:login,用来判断用户密码是否正确。
    代码:
    1、redux内:
    actionType:AUTH_SUCESS
    actionCreator:
    authSucess(return {type:AUTH_SUCESS,data:data})
        export function login(data) {
                return dispatch=>{
                    axios.post('./user/login',data).
                        then(res=>{
                    //请求成功,提交成功actionCreator:actionCreator
                    if(res.status === 200 && res.data.code===0){
                            dispatch(actionCreator(res.data.data))
                     }
                    // 请求失败,提交失败actionCreator:errorMsg
                    else{
                            dispatch(errorMsg(res.data,msg))
                    }
                })
             }
        }
        function reducer(state,action){
                switch(action.type){
                        case AUTH_SUCESS:
                            return  {...state,msg:'',redirect:getRedirectPath(action.data),...action.data}
                    default:
                            return state
                 }
        }

2、请求通过之后跳转页面。


二、注册:

1、逻辑和登录差不多,就不详细说了。(提交后台注册信息、跳转页面)


三、完善信息页面

两个组件 : geniusinfo/bossinfo
流程
用户添加头像和简介等相关信息(设置组件内部的state,设置对应字段) => 点击保存 => 请求接口、post传递数据(提交对应的action,传入请求到的值) => 更改redux(这一步是确保点击按钮后渲染到正确组件的关键!再次说明:跳转到哪是通过redirectTo决定的!!!)

//组件内部
this.state = {
            title : '',
            company : '',
            money : '',
            desc : ''
}
<Button  onClick={ ()=>{ this.props.update(this.state) }  }
  >保存</Button>
// redux

// 账号补全信息补全信息
export function update(state) {
    return dispatch=>{
        axios.post('/user/update',state).
            then(res=>{
                if(res.status === 200 && res.data.code===0){
                    // 后台返回的信息:user和用于跳转的type
                    dispatch(authSucess(res.data.data))
                    console.log(res.data.data)
                }else{
                    dispatch(errorMsg(res.data.msg))
                }
            })
    }
}
// reducer
  case AUTH_SUCESS:
    return {...state,msg:'',redirectTo:getRedirectPath(action.data),...action.data,pwd:''}

四、头像选择组件:

要给父组件bossinfo/geniusinfo传入选择的是哪一个图片,方便父组件记录到redux里面。

其实是父组件想从子组件中拿到数据,那么也是一样,在父组件设置自定义属性,写一个方法,子组件通过props接收该方法并传入具体参数即可

// 子组件:获取props
  <Grid 
   onClick={elm=>{
     this.props.selectAvator(elm.text)
   }}
  />  
// 父组件传递
<AvatarSelector
   selectAvator={(imgname)=>{
    this.setState({
    avatar : imgname
    })
  }}
></AvatarSelector>

boss组件

请求接口,获取genius数据后渲染到页面,请求到的数据都统一放到组件自身的state里,方便处理。然后将state的数据进行循环渲染即可!


使用redux管理牛人列表

因为BOSS和求职的卡片信息是一样的,所以我们可以将其封装成组件方便使用。

将数据放到redux的步骤:

// 1
const USER_LIST = 'USER_LIST'

const initState = {
    userList : []
}
// 3
export function chatuser(state=initState,action){
    switch(action.type){
        case USER_LIST :
            // 这个状态随时可能加其他的数据,所以需要先展开
            return {...state,userList:action.payload}
        default:
            return state
    }
}
// 2
export function userList(data){
    return {type:USER_LIST,payload:data}
}
// 4
export function getUserList(type){
    return dispatch=>{
        axios.get('/user/list?type='+type).
        then(res=>{
            if(res.data.code==0){
                dispatch(userList(res.data.data))
            }
        })
    }
}

boss列表和组件优化

boss和gennius的用户展示是一样的,所以将用户展示这部分单独抽离成一个组件:usercard。


个人中心信息展示

我们之前已经把用户所有的数据,通过get请求'/user/info'接口,将获取的数据都保存在了redux的state中,在redux的调试工具中即可查看到。所以用户中心这个页面是非常好做的,直接从redux获取数据,展示出来,加上需要的按钮即可。


在个人中心里退出登录

关键是清除cookie。npm下载browserCookie,并在页面中引入。
1、逻辑:点击退出登录按钮清除cookie

    logout(){
        console.log('logout')
        browserCookies.erase('userid')
    }

2、具体实现
使用Modal组件,点击时调用以下代码

alert('注销', '确认退出登录吗', [
            { text: '取消', onPress: () => console.log('cancel') },
            { text: '确认', onPress: () => {
                browserCookies.erase('userid')
                window.location.href = window.location.href
            }},
        ])

现在是清空cookie,刷新页面实现了跳转。
这样的体验不好。
所以我们在注销时清空redux数据这个方法较好。

  // 退出登录 :把初始信息放入
        case LOGOUT : 
            return {...initState,redirectTo:'/login'}

Socket.io

屏幕快照 2018-07-16 上午6.47.29.png
屏幕快照 2018-07-16 上午6.49.33.png

socket.io前后端联通,消息发送流程梳理

注:socket是当前的请求,io是全局的

流程
1、后端io.on建立connection链接
2、前端触发 socket.emit,方法:sendmsg,携带数据,发起成功之后,后端就可以收到消息了。
3、后端socket.on监听前端发送的消息sendmsg,在方法体内发送到全局接收io.emit('recvmsg',data)
4、前端在componentDidMount中socket.on监听recvmsg,获取data,将数据更新到组件中

1、后端express : 引入socket.io,和express关联

const app  = express()
//work with express
Const server = require('http').Server(app)
const io = require('socket.io')(server)
// 参数:socket,当前的链接;io,全局链接
io.on('connection',function(socket){
    console.log('user login')
    // 监听前端发送的消息,方法就是前端的方法
    socket.on('sendmsg',function(data){
        const {form , to , msg} = data
        const chatid = [form,to].sort().join('_')

        // data是前端发送过来的消息
        console.log(data)
        // 发送到全局,每个人都是接受的状态
        //io.emit('recvmsg',data)
    })
})
server.listen(9093,function(){
    console.log('Node app start at port 9093')
})

2、前端
发起链接,在conponentMount中,也可以放在外面直接引入;
发起成功之后,后端就可以收到消息了。

// socket客户端
import io from 'socket.io-client'
// 因为跨域了,所以需要写明链接的地址
const socket = io('ws://localhost:9093')

// 消息发送到后端
handelSubmit(){
//发送state到后端
socket.emit('sendmsg',{text:this.state.text})
}
// 监听sendmsg事件,监控消息
socket.on('recvmsg',function(data)){
console.log(data)
}
3、聊天信息展示,在componentDidMount中监听

 componentDidMount(){
        //  socket.监听recvmsg,接收消息
        // socket.on('recvmsg',data=>{
           this.setState({
                msg:[...this.state.msg,data.text]
            })
        })  
       // 加载消息列表   
        this.props.getMsgList()  
    }

聊天页面redux链接 : chat.redux.js

1、state设置chatmsg消息列表和unread未读信息字段;
2、进入聊天页面,axios获取消息列表,并将信息并入state。

!!!用户识别:使用用户的ID来识别用户
1、发送方 : user中获取id
2、接收方:在usercard组件中,在点击用户头像时,在地址栏中加入用户ID

this.props.history.push(`/chat/${v._id}`)

1.点击发送按钮,传给后台的字段 : from,to,msg
2.组件即将挂载时recvMsg,渲染对话

注意:后端返回的是全部消息,分组需要前后端协商将两个id拼接进行校验!
点击提交,将from,to,msg传给后端,后端接收到之后将消息广播到全局。通过地址栏获取的id(to)和redux的to比较,如果相同,就说明是接收方,然后将这条消息显示在左边,否则就是自己的消息,显示在右边。通过对比chatId,就可以定位到这两个人的消息,避免消息错乱。

消息列表:消息分组,将chatmsg(返回的是全部的消息)的数据根据chaid分组,这样就得到了对话分组。
chatList=this.props.chat.chatmsg.filter( v=>v.chatid===chatid )

未读消息数量:chatList(根据v.chatid分组)中 : to = 当前登录用户,说明消息是本人发送

未读消息清零: 进入聊天页面,向后端发送请求,让后端标识一下,将read字段标识为true.
后端返回from(对方),to(当前登录的userid)

相关文章

网友评论

      本文标题:项目详细说明

      本文链接:https://www.haomeiwen.com/subject/febxpftx.html