Javascript 第一次正确获取数据时,当用户移动到彼此聊天时,状态值未刷新,显示过去+;当前用户聊天

Javascript 第一次正确获取数据时,当用户移动到彼此聊天时,状态值未刷新,显示过去+;当前用户聊天,javascript,node.js,reactjs,socket.io,Javascript,Node.js,Reactjs,Socket.io,我是react.js和node.js的新手,我正在尝试构建聊天应用程序,我还使用了socket.io。其中,当任何用户点击用户聊天时,都会调用chat.js组件文件,第一次显示聊天消息的正确抓取结果,当用户点击与另一个用户聊天时,我正在通过用户聊天+当前用户聊天。 我检查了从后端节点服务器获取的数据是否正确,react.js出现问题 dashboard.js import React, { useEffect, useState } from "react" import {

我是react.js和node.js的新手,我正在尝试构建聊天应用程序,我还使用了socket.io。其中,当任何用户点击用户聊天时,都会调用chat.js组件文件,第一次显示聊天消息的正确抓取结果,当用户点击与另一个用户聊天时,我正在通过用户聊天+当前用户聊天。 我检查了从后端节点服务器获取的数据是否正确,react.js出现问题

dashboard.js

import React, { useEffect, useState } from "react"
import { Container,Row,Col,Button} from 'react-bootstrap'
import {fetchUsers} from '../services/services'
import {useHistory} from 'react-router-dom'
import Chat from "./Chat"
function Dashboard() {
    const [users,setUsers]=useState([])
    const senderId = localStorage.getItem("senderId");
    const history=useHistory()
    const setLogout=()=>{
        localStorage.setItem("loggedin", false);
        history.push('/signin');
    }

    /*
    fetchUsers function will be called for fetching all users, except the current logged-in user.
    */
   
    useEffect(()=>{
        fetchUsers(senderId).then(res=> setUsers(res.data.message))
    })

    var receiverId;
    function handleInput(id){
        receiverId=id
        console.log(receiverId)
        localStorage.setItem("receiverId",id)
    }
    
    return (
        <div>
            <Container fluid>
                <Row className="p-2">
                    <Col>
                    <h1 align="left">Login successful</h1> 
                    </Col>
                    <Col md={{span:2,offset:4}}>
                        <Button onClick={setLogout} className="btn btn-danger btn-block">Logout</Button>
                    </Col>
                </Row>
                <Row className="p-4">
                    <Col md={3}>
                        <h3>
                            List of Users
                        </h3>
                        {
                            users.map(
                                e=>{
                                    return <Row className="pt-2 pb-2" key={e._id} onClick={()=>handleInput(e._id)}>
                                                <Col>
                                                    <img className="ui avatar image" alt={e.username} src={"https://ui-avatars.com/api/?name="+`${e.username}`}/>
                                                    <span>{e.username}</span>
                                                </Col>
                                           </Row>
                                    }
                            )
                        }
                    </Col>
                    <Col md={9}>
                        {receiverId=="" && <Chat ></Chat>}
                    </Col>
                </Row>
            </Container>
        </div>
    )
}

export default Dashboard
import React,{useffect,useState}来自“React”
从“react bootstrap”导入{容器、行、列、按钮}
从“../services/services”导入{fetchUsers}
从“react router dom”导入{useHistory}
从“/Chat”导入聊天
函数仪表板(){
const[users,setUsers]=useState([])
const senderId=localStorage.getItem(“senderId”);
const history=useHistory()
const setLogout=()=>{
setItem(“loggedin”,false);
history.push('/sign');
}
/*
将调用fetchUsers函数获取除当前登录用户之外的所有用户。
*/
useffect(()=>{
fetchUsers(senderId).then(res=>setUsers(res.data.message))
})
var受体;
函数handleInput(id){
接收方id=id
控制台日志(接收方ID)
localStorage.setItem(“receiverId”,id)
}
返回(
登录成功
注销
用户名单
{
users.map(
e=>{
返回handleInput(e.\u id)}>
{e.username}
}
)
}
{receiverId==“”&}
)
}
导出默认仪表板
chat.js

import React, { useEffect, useRef, useState } from "react"
import io from "socket.io-client"
import { Row,Col,Form} from 'react-bootstrap'
import {useHistory} from 'react-router-dom'
import {fetchUserById,fetchRoom,fetchChats} from '../services/services'
export default function Chat() {
    const history=useHistory()

    const [username,senderId,receiverId] = [localStorage.getItem("username"),localStorage.getItem("senderId"),localStorage.getItem("receiverId")];

    console.log(receiverId)

    const socketRef = useRef();

    const [chat,setChat]=useState([]);
    const [ oldChat, setOldChat ] = useState([]);
    const [receiver, setReceiver] = useState("");

    useEffect(()=>{
        /*
        fetchUserById is called to find receiver id when user click on username.
        */
        fetchUserById(receiverId).then(res=> setReceiver(res.data.message[0].username))
    },[receiverId])

    // once we get result from fetchUserById it will set the receiver name into receiver state, and here we assign it to receiverUser
    const receiverUser=receiver

    const [ state, setState ] = useState({ senderId:senderId ,message: "", username: username,receiverId:receiverId,roomId:"",receiverUser:receiverUser})
    const roomId1=senderId.substr(12);
    const roomId2=receiverId.substr(12);
    /*
    fetchRoom will find the room based on current user's last 12 characters, and receiver user's last 12 characters
    where roomId1 and roomId2 both will passed into fetchRoom, 
    where roomId1, is current active user + receiver user's IDs of last 12-12 characters, total 24 characters
    same as above, roomId2 have reverse of roomId1, here receiver's + current active user 12-12 characters, total 24 characters.
    it will pass to fetchRoom and check if any chat found within this room, it will return the roomId whatever we have in database,
    else not found then it will return roomId1 as per the current user. 
    */
    useEffect(
        () => {
            fetchRoom(roomId1,roomId2).then(res=> {
                localStorage.setItem("roomId",res.data.message);
                setState({senderId,message:"",username,receiverId,roomId:res.data.message,receiverUser})
            })
            let roomId=localStorage.getItem("roomId")
            
            socketRef.current = io.connect("http://localhost:4000" ,{transports: ['polling']})
            socketRef.current.on("message", ({senderId,username, message,receiverId,roomId,receiverUser }) => {
                setOldChat([ ...oldChat, { senderId,username, message,receiverId,roomId,receiverUser } ])
            })
            return () => socketRef.current.disconnect()
        },[oldChat]
    )
    // saving roomId into localStorage.
    const roomId=localStorage.getItem("roomId")
    useEffect(() => {
        fetchChats(roomId,senderId,receiverId).then(res=>{
         if(res.data.status===200){
            setOldChat([...oldChat,res.data.message])
            // console.log(oldChat)
         } else{
             setOldChat([]);
            console.log("inside else")
             setOldChat([...oldChat,res.data.message])
            // console.log(res.data.message)
         }
        })
     }, [roomId, senderId, receiverId]);

    // onTextChange is helps to change value of message textbox.
    const onTextChange = (e) => {
        setState({ ...state, [e.target.name]: e.target.value })
    }

    /*
    on click onMessageSubmit, it will take state value, and check message is empty then it will give alert,
    else it will emit message event.
    */
    const onMessageSubmit = (e) => {
        const { senderId, message,receiverId,roomId,receiverUser } = state
        
        if(message===""){
            e.preventDefault()
            alert("please enter message")
        }else{
            socketRef.current.emit("message", {
                senderId,username,message,receiverId,roomId, receiverUser
            })
            setChat([...chat,{senderId,username,message,receiverId,roomId,receiverUser}])
            e.preventDefault()
        }
    }
    
    /*
    renderChat method will take oldChat state values
    we had used ternary operator for rendering values
    but, if senderId is equal to current userId then it will print with sender/username,else it will print message of receiver. 
    */
    const renderChat = () => {
        console.log("renderChat",oldChat.length)
        return oldChat.length && oldChat.map((e)=>{
            return e.length ? e.map((ee)=>{
                if(ee.senderId===senderId){
                    return  <Row key={ee._id}>
                                <div style={{display:"flex",flexDirection:"row"}} className="p-1">
                                        <img className="ui avatar image" alt={username} src={"https://ui-avatars.com/api/?name="+`${username}`}/><b>{username}</b>:{ee.message}
                                </div>
                            </Row>
                }
                else{
                    return  <Row key={ee._id}>
                                <div style={{marginLeft:"auto",marginRight:0}} className="p-1">
                                    <div style={{display:"flex",flexDirection:"row-reverse",justifyContent: "flex-end"}}>
                                        <img className="ui avatar image" alt={receiverUser} src={"https://ui-avatars.com/api/?name="+`${receiverUser}`}/><b>{receiverUser}</b>{ee.message}:
                                    </div>
                                </div>
                            </Row>
                }
            }):""
        })
    }

    /*
    renderCurrentChat works as similar to renderChat as you can check above fucntion,
    it takes the current chat of user, if senderId is equal to current userId then it will print with sender/username,
    else it will print message of receiver.
    */
    const renderCurrentChat = () => {
        console.log("renderCurrentchat",chat.length)
        return chat.length ? chat.map((e)=>{
            console.log(e)
                if(e.senderId===senderId){
                    return  <Row key={Math.floor(Math.random() * 999) }>
                                <div style={{display:"flex",flexDirection:"row"}} className="p-1">
                                        <img className="ui avatar image" alt={username} src={"https://ui-avatars.com/api/?name="+`${username}`}/><b>{username}</b>:{e.message}
                                </div>
                            </Row>
                }
                else{
                    return  <Row key={Math.floor(Math.random() * 999)}>
                                <div style={{marginLeft:"auto",marginRight:0}} className="p-1">
                                    <div style={{display:"flex",flexDirection:"row-reverse",justifyContent: "flex-end"}}>
                                        <b>{receiverUser}</b><img className="ui avatar image" alt={receiverUser} src={"https://ui-avatars.com/api/?name="+`${receiverUser}`}/>{e.message}:
                                    </div>
                                </div>
                            </Row>
                }
            
        }):""
    }
    return (
            <Row className="">
                {/* 
                form having senderId, username, roomId and message
                in senderId current active users Id will be displayed in disabled textbox,
                where on username it shows current active username in disabled textbox,
                in roomId it will get based on  fetchRoom function which I had discribed above,
                if user having chat then it will receive roomId, and display here in textbox with disabled,
                in message it having default state value "" empty and it will be change when it based onTextChange event
                and at last button, on submit button onMessageSubmit will be fired/called.
                */}
                <Col md={8}>
                    <div>
                        {/* chat heading to acknowledge who talking to whom */}
                        <h1>Chat log history</h1>
                        <p> {username} is talking to {receiverUser}</p>
                        <div style={{maxHeight: "495px",overflow: "auto"}}> 
                            {/* prints all message having in oldChat State */}
                            <div className="pt-0 pl-5 pr-5 pb-0">
                                {renderChat()}
                            </div>
                            {/* prints all message having in chat State */}
                            <div className="pt-0 pl-5 pr-5 pb-0">
                                {renderCurrentChat()}
                            </div>
                        </div>
                    </div>
                </Col>
                <Col md={4}>
                    <form onSubmit={onMessageSubmit}>
                        <h1>Send message</h1>
                        <div hidden>
                            <input type ="text" name="senderId" disabled  value={state.senderId} label="SenderId" />
                        </div>
                        <div className="p-1">
                            <Form.Control type="text" name="username" placeholder={state.username} value={state.username} readOnly/>
                        </div>
                        <div hidden>
                            <input type ="text" name="roomId" disabled  value={state.roomId} label="RoomId" />
                        </div>
                        <div className="p-1">
                        <Form.Control type="text" name="message" placeholder="enter your message....." onChange={(e) => onTextChange(e)} value={state.message} id="outlined-multiline-static" variant="outlined" label="Message"/>
                        </div>
                        <button className="btn btn-primary p-2 m-2">Send Message</button>
                    </form>
                </Col>
                
                                    
            </Row>
    )
}
import React,{useffect,useRef,useState}来自“React”
从“socket.io客户端”导入io
从“react bootstrap”导入{Row,Col,Form}
从“react router dom”导入{useHistory}
从“../services/services”导入{fetchUserById、fetchRoom、fetchChats}
导出默认函数Chat(){
const history=useHistory()
const[username,senderId,receiverId]=[localStorage.getItem(“用户名”)、localStorage.getItem(“senderId”)、localStorage.getItem(“receiverId”);
控制台日志(接收方ID)
const socketRef=useRef();
const[chat,setChat]=useState([]);
const[oldChat,setOldChat]=useState([]);
const[receiver,setReceiver]=useState(“”);
useffect(()=>{
/*
当用户单击用户名时,调用fetchUserById查找接收方id。
*/
fetchUserById(receiverId).then(res=>setReceiver(res.data.message[0].username))
},[接收方])
//一旦我们从fetchUserById获得结果,它将把接收方名称设置为接收方状态,在这里我们将其分配给receiverUser
const receiverUser=接收方
const[state,setState]=useState({senderId:senderId,message:,username:username,receiverId:receiverId,roomId:,receiverUser:receiverUser})
const roomId1=senderId.substr(12);
const roomId2=收款人substr(12);
/*
fetchRoom将根据当前用户的最后12个字符和接收方用户的最后12个字符查找文件室
roomId1和roomId2都将被传递到fetchRoom,
其中roomId1是最近12-12个字符的当前活动用户+接收方用户ID,总共24个字符
如上所述,roomId2与roomId1相反,此处接收器+当前活动用户12-12个字符,总共24个字符。
它将传递到fetchRoom并检查是否在该聊天室中找到任何聊天,它将返回数据库中的roomId,
否则将根据当前用户返回roomId1。
*/
使用效果(
() => {
fetchRoom(roomId1,roomId2)。然后(res=>{
setItem(“roomId”,res.data.message);
setState({senderId,message:”,用户名,receiverId,roomId:res.data.message,receiverUser})
})
让roomId=localStorage.getItem(“roomId”)
socketRef.current=io.connect(“http://localhost:4000“,{transports:['polling']}
socketRef.current.on(“message”,({senderId,username,message,receiverId,roomId,receiverUser})=>{
setOldChat([…oldChat,{senderId,用户名,消息,receiverId,roomId,receiverUser}])
})
return()=>socketRef.current.disconnect()
},[oldChat]
)
//正在将roomId保存到本地存储中。
const roomId=localStorage.getItem(“roomId”)
useffect(()=>{
获取聊天记录(roomId、senderId、receiverId)。然后(res=>{
if(res.data.status==200){
setOldChat([…oldChat,res.data.message])
//console.log(oldChat)
}否则{
setOldChat([]);
console.log(“其他内部”)
setOldChat([…oldChat,res.data.message])
//console.log(res.data.message)
}
})
},[roomId、senderId、receiverId]);
//onTextChange有助于更改消息文本框的值。
const onTextChange=(e)=>{
setState({…state[e.target.name]:e.target.value})
}
/*
单击MessageSubmit,它将
fetchChats(roomId,senderId,receiverId).then(res=>{
         if(res.data.status===200){
            setOldChat([...oldChat,res.data.message])
            // console.log(oldChat)
         } else{
             setOldChat([]);
            console.log("inside else")
             setOldChat([...oldChat,res.data.message])
            // console.log(res.data.message)
         }
        })