react.js+express socket.io 를 이용한 room 채팅

코딩하는 어린콩·2021년 10월 29일
0

React

목록 보기
1/2

이번에 두 개의 프로젝트를 만들게 되었는데 이 두 프로젝트 두 개다 실시간 채팅 기능이 필요합니다. ㅠㅠ

그래서 socket.io 를 이용한 실시간 채팅 기능을 만들어보려고 노력해 보았습니다.

express설치와 기본설정 react의 설치와 기본 설정은 건너뛰겠습니다.

설명에 앞서 app.js에서 뿌려지는 message.js와 express서버를 만드는 server.js의 예로 설명을 해보겠습니다.

일단 socket.io는 중요한 3가지를 기억을 해야 됩니다.

  • emit
  • join
  • on

첫 번째로 emit입니다.

emit은 단어 그대로 이벤트를 발생시키는 것입니다.

예를 들어

server.js에서

socket.emit('your id',socket.id);

라는 코드가 있고

message.js에서

socket.on("your id",id=>{
            this.setState({
                yourID:id
            })
        })

이라는 코드가 있습니다. 이 말은 server.js에서 "your id"라는 장소로 이벤트를 발생시키고 그 이벤트 결과 message.js에서

"your id"라는 장소의 소켓 코드에서 server.js의 socket.id의 값을 id에 저장시킨 뒤에 message.js의 state값 yourID에 저장시키는 코드가 됩니다.

여기서 on이라는 것이 나오는데 이것이 emit로 인해 발생되는 이벤트를 받는 곳이라고 생각하면 될 거 같습니다.

그다음으로는 join입니다.

사실 간단하면서도 가장 제가 헷갈렸던 부분입니다.

채팅을 주고받는 것까지는 알겠는데 방을 어떻게 나눈다는 거지?

유저와 유저가 대화한 내용을 db에도 담으려고 했었기 때문에 room을 구분하는 것이 굉장히 어렵게 느껴졌었는데

join도 하나의 이벤트라고 생각하면 간단합니다. socket이 알아서 방을 관리해주는 것입니다.

자 이제 제가 만든 코드를 보시겠습니다.

처음으로는 server.js입니다.

const express = require('express')
const app = express()
const port = 3001
var http = require('http').createServer(app);
const io = require('socket.io')(http);

io.on("connection", function(socket) {
    socket.on('room', function (user_id) { //I use the user_id of the user to create room

        socket.join(user_id,()=>{
            console.log(user_id+'방입장');
        });
    });
    console.log('a user connected');
    socket.on("send message",messageobject=>{
        console.log(messageobject.name);
        console.log(messageobject.body);
        io.to(messageobject.name).emit("message",messageobject.body);
    })
    
})


http.listen(port, () => console.log(`Example app listening on port ${port}!`))

첫 번째 io.on("connection", ~ 이 부분은 소켓 연결을 시켜주는 부분입니다.

그다음 여기서 socket.on('room')이 나오게 되는데 이것은 방을 만들어주는 부분이라고 이해하시면 됩니다.

만약 jybin96이라는 사용자가 socket.emit 하고 그 안에 jybin96이라는 user_id를 담아서 신호를 보낸다면

이 코드는 콜백 함수 안에서 jybin96이라는 방을 입장하게 됩니다.

2번째

socket.on("send message")라는 코드를 보시면 이 코드는 jybin96이라는 사용자가 socket.emit 하고 그 안에 자신의 사용자 이름 그리고 메시지를 보내는 부분입니다.

저기서 이제 io.to(messageobject.name). emit부분이 중요한데 to() 부분은 jybin96이라는 방에 참가하는 모든 사용자에게 메시지를 보내주는 부분이라고 생각하시면 될 거 같습니다.

export default class Message extends React.Component{
    constructor(props){
        super(props);
        this.state = {
            anchorEl : null,
            open:false,
            chat:'',
            yourID:'',
            messages:[],
            message:""
        }
        this.handleClose = this.handleClose.bind(this);
        this.handleopen = this.handleopen.bind(this);
        this.keyboard = this.keyboard.bind(this);
        this.onChange =this.onChange.bind(this);
    }
    receivemessage=(message)=>{
        this.setState({
            messages:[...this.state.messages,message]
        })
    }
    componentWillMount(){
        const user_id = "jybin96"
        socket.emit('room',user_id);
        socket.on("your id",id=>{
            this.setState({
                yourID:id
            })
        })
        socket.on("message",(message)=>{
            console.log(message);
            this.receivemessage(message);

        })
    }
    onChange(e){
        this.setState({
            message: e.target.value,
          });
          console.log(this.state.message);
          
    }
    keyboard(e){
        console.log(e.keyCode);
        if(e.keyCode == 13){
            console.log(`엔터키누름 :  ${this.state.chat}`);    //여기서 전송
            const messageobject = {
                name:"jybin96",
                body:this.state.message,
                id:this.state.yourID,
            }
            this.setState({
                message:""
            })
            socket.emit("send message",messageobject);
        }
       
    }
    handleClose (e){
       
        this.setState({
            anchorEl:null
        })
    }

    handleopen(e){
        this.setState({
            anchorEl: e.currentTarget,
            open:Boolean(e.currentTarget)
        })
    } 
   
    render(){
        const {handleClose,handleopen,keyboard,onChange} =this;
        const {classes} = this.props;
        return(
            <div>
               <div>
                   {this.state.messages.map((message,index)=>{
                           return(
                               <div>
                                   {index}
                                   {message}
                                </div>
                           )
                       
                   })}
               </div>
                <label>입력</label>
                    <TextField id="outlined-basic" variant="outlined" placeholder="입력하세요." onKeyDown={keyboard} onChange={onChange} value={this.state.message}/>
            </div>
            
        )
    }
} 

이 코드는 Message.js코드입니다.

이 코드를 복붙 하셔서 실행시키려면 material-ui를 사용하였기 때문에 바로 안 돌아갈 것입니다.

npm install @material-ui/core

설치를 하시길 바랍니다.

자 이 코드를 보시면 차근차근 이해가 되실 거라고 믿습니다.

이 코드만으로는 2개의 방을 만들어 사용이 안 됩니다 ㅎㅎ

그래서

import React, { useRef } from 'react';
import TextField from '@material-ui/core/TextField';
import io from 'socket.io-client';


const socket = io('http://localhost:3001'); 

const style  = {
    paper: {
        height: "auto",
        width: "auto",
    },
    
  };
export default class Message2 extends React.Component{
    constructor(props){
        super(props);
        this.state = {
            anchorEl : null,
            open:false,
            chat:'',
            yourID:'',
            messages:[],
            message:""
        }
        this.handleClose = this.handleClose.bind(this);
        this.handleopen = this.handleopen.bind(this);
        this.keyboard = this.keyboard.bind(this);
        this.onChange =this.onChange.bind(this);
    }
    receivemessage=(message)=>{
        this.setState({
            messages:[...this.state.messages,message]
        })
    }
    componentWillMount(){
        const user_id = "snsk3779"
        socket.emit('room',user_id);
        socket.on("your id",id=>{
            this.setState({
                yourID:id
            })
        })
        socket.on("message",(message)=>{
            console.log(message);
            this.receivemessage(message);

        })
    }
    onChange(e){
        this.setState({
            message: e.target.value,
          });
          console.log(this.state.message);
          
    }
    keyboard(e){
        console.log(e.keyCode);
        if(e.keyCode == 13){
            console.log(`엔터키누름 :  ${this.state.chat}`);    //여기서 전송
            const messageobject = {
                name:"snsk3779",
                body:this.state.message,
                id:this.state.yourID,
            }
            this.setState({
                message:""
            })
            socket.emit("send message",messageobject);
        }
       
    }
    handleClose (e){
       
        this.setState({
            anchorEl:null
        })
    }

    handleopen(e){
        this.setState({
            anchorEl: e.currentTarget,
            open:Boolean(e.currentTarget)
        })
    } 
   
    render(){
        const {handleClose,handleopen,keyboard,onChange} =this;
        const {classes} = this.props;
        return(
            <div>
               <div>
                   {this.state.messages.map((message,index)=>{
                           return(
                               <div>
                                   {message}
                                </div>
                           )
                       
                   })}
               </div>
                <label>입력</label>
                    <TextField id="outlined-basic" variant="outlined" placeholder="입력하세요." onKeyDown={keyboard} onChange={onChange} value={this.state.message}/>
            </div>
            
        )
    }
} 

message2.js를 더사용합니다.

코드는 똑같지만 message.js는 방이 jybin96이고

message2.js는 방이 sns k3779입니다 ㅎㅎ

이것을 사용하여 실행시키면

이렇게 됩니다. 참고로 라우팅을 '/' 은 message2.js이고 '/pin'은 message.js입니다. ㅎㅎ

이렇게 해서 각각 textfield에 글을 쳐보면

이런 식으로 2개의 방으로 2명씩 각각 소켓통신을 하는 것을 볼 수 있습니다.

제가 독학으로 구글링 하면서 찾아본 내용이라 코드가 엉망 일수 있습니다. ㅠㅠ

그래도 뭔가 하나를 깨우쳤다는 느낌을 받고 역시 코딩은 재밌는 거 같습니다.

이제 프로젝트 2개의 채팅 기능도 만들 수 있을 거 같습니다.

0개의 댓글

관련 채용 정보