(수근수근)

[react] socket.io 로 채팅 만들기 본문

web/React

[react] socket.io 로 채팅 만들기

InformationFarm 2021. 1. 20. 13:33

다음 글은 아래의 유튜브 영상을 보고 정리한 내용입니다.

code : https://github.com/NikValdez/ChatAppTut
출처: www.youtube.com/watch?v=CgV8omlWq2o

react - chatting -app

완성된 채팅앱

 

 


목차

  • 전체 프로젝트 구조 
  • socket.io 모듈 및 function
  • server 소스
  • Client 소스
  • REACT STUDY
    • function vs class
    • useEffect & useState
    • cors Error 해결
  • 추가) room 나누기

전체 프로젝트 구조

 

다음은 전체 프로젝트 구조입니다.

Client와 Server가 소켓통신을 통해서 서로 통신을 주고 받습니다. 

 

 

  • chat 폴더 : Client 역할
  • Server 폴더 : server역할

 

 

 

 

Socket.io 모듈 및 function

  • socket.io란
    socket.io란 websocket기반으로 클라이언트와 서버간의 양방향 통신을 가능하게 해주는 모듈입니다.

    기본적인 socket의 연결, 해제기능들을 자바스크립트로 가능하게 만든 모듈이라 생각하시면 편할 것 같습니다.
    기본적인 socket의 실행흐름에 대해 알고 사용하는 것이 더 의미가 있을 것 같습니다. 

https://song-yoshiii.tistory.com/3

  • socket 핵심 function

    emit : 데이터 전송 (서버-> 클라이언트 / 클라이언트  -> 서버)
    on :데이터를 받는다 (서버-> 클라이언트 / 클라이언트 -> 서버)

Server 설정 및 소스

  • 환경 설정(server폴더에서 아래의 명령어 실행 )
    • npm install express
    • npm install cors
    • npm install nodemon
    • npm install socket.io 
// path : chat/server/index.js

const app = require('express')()
const server = require('http').createServer(app)
const cors = require('cors')
const io = require('socket.io')(server,{
    cors : {
        origin :"*",
        credentials :true
    }
});


io.on('connection', socket=>{
    socket.on('message',({name,message}) => {
        io.emit('message',({name, message}))
    })
})

server.listen(4000, function(){
    console.log('listening on port 4000');
})
  • 제공되는 코드에서는 cors 부분이 빠져있는데 그대로 코드를 실행한 경우 다음과 에러가 났다.
    cors : { origin : "*", credentials : true} 를 코드에 추가 시켜서 문제해결 

 

Client 설정 및 소스

  • 환경설정 (CHATTING폴더에서 아래의 명령어 실행)
    • npx create-react-app chat
    • cd chat 
    • npm install socket.io-client   //socket client모듈
    • npm install @material-ui/core  //react UI입니다
    • App.css 내용은 위에 깃허브에 있습니다.
// paht  : CHATTING/chat/App.js

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

const socket =  io.connect('http://localhost:4000')

function App() {
  const [state, setState] = useState({message:'', name:''})
  const [chat,setChat] =useState([])

  useEffect(()=>{
    socket.on('message',({name,message})=>{
      setChat([...chat,{name,message}])
    })
  },[])

  const onTextChange = e =>{
    setState({...state,[e.target.name]: e.target.value})
  }

  const onMessageSubmit =(e)=>{
    e.preventDefault()
    const {name, message} =state
    socket.emit('message',{name, message})
    setState({message : '',name})
  }


  const renderChat =()=>{
    return chat.map(({name, message},index)=>(
      <div key={index}>
        <h3>{name}:<span>{message}</span></h3>
      </div>
    ))
  }

  return (
    <div className='card'>
      <form onSubmit={onMessageSubmit}>
        <h1>Message</h1>
        <div className="name-field">
          <TextField 
          name ="name" 
          onChange={e=> onTextChange(e)} 
          value={state.name}
          label="Name"/>
        </div>
        <div >
          <TextField 
          name ="message" 
          onChange={e=> onTextChange(e)} 
          value={state.message}
          id="outlined-multiline-static"
          variant="outlined"
          label="Message"/>
        </div>
        <button>Send Message</button>
      </form>
      <div className="render-chat">
        <h1>Chat log</h1>
        {renderChat()}
      </div>
    </div>
  );
}

export default App;

 

REACT STUDY

[ class vs function ]

Hooks이 나오기 전에 class component는 react component의 모든기능이 가능했지만

function에서는 제약사항이 많았다. 

최신 리액트에서는 hooks이 등장하면서 funcion component 기존 class의 작업이 가능해졌다

hook이란?
class 없이 state를 사용할 수 있는 새로운 기능

 

[ useState ]

  • 동적인 상태인 state를 관리하기 위해 나온 HOOK
  • 함수형 컴포넌트에서도 state관리가 가능해짐

기존 클래스 컴포넌트에서 state관리

초기값 설정의 constructor에서 진행해주었고, 상태값을 this를 통해서 불러올 수 있었다.

class Example extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }

  render() {
    return (
      <div>
        <p>You clicked {this.state.count} times</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          Click me
        </button>
      </div>
    );
  }
}

 

반면에 함수 컴포넌트에서는 상태값을 가지고 오기 위해서는 props로 데이터를 전달해주어야했다.

이를 해결하기 위해 Hook이라는 것을 소개 했고 useState를 활용하여 function component에서도

이제 state의 특징을 사용할 수 있다.

 

import React, { useState } from 'react';

function Example() {
  // 새로운 state 변수를 선언하고, count라 부르겠습니다.
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

 

[ useEffect ]

  • useEffect render() 가 끝났을 때 ,렌더가 실행될때마다 실행된다
  • 클래스의 life cycle 에서 componentDidMount/ componentDidUpdate 를 대신하는 것이다.
  • 렌더링 이후에 작업되는 것으로써 네트워크통신이나, 컴포넌트와 상관없는 것들을 변경될 때 사용된다
  • useEffect는 여러개 설치할 수 있다.
  • useEffect의 리턴값에 함수를 제공하면 마무리하는 작업을 진행할 수 있다.(clean up)
  • 두번째 원소값을 배열에 넣으면, 그 값이 바뀌지 않으면 useEffect작업을 진행하지 않는다. 
Comments