Bin's Blog

[유데미x스나이퍼팩토리] 10주 완성 프로젝트 캠프 25일차 - 리액트(5) 본문

학습일지

[유데미x스나이퍼팩토리] 10주 완성 프로젝트 캠프 25일차 - 리액트(5)

hotIce 2023. 6. 30. 19:48
728x90

 

1️⃣ useReducer

👉 React 내장 훅 중에 하나로, 간단한 컴포넌트 상태를 관리할 때는 useState()를 사용하는 반면에 보다 복잡한 컴포넌트 상태를 관리하는데 useReducer()가 사용된다.

👉 reduce함수에 분리시킴으로써 복잡한 상태 로직을 캡슐화하는데 도움이 된다. 

 

👉 기본 형태

const [state, dispatch] = useReducer(reducer, initial);
  • reducer: (state, action) => newState 형태의 함수다. 이 함수는 현재 상태와 분배된 액션을 받아 새 상태를 반환한다.
  • initial: Reducer에 전달한 초기 상태 값이다. 
  • useReducer훅은 상태 값(state)과 해당 상태를 변경하기 위한 디스패치 함수("dispatch")를 배열로 반환한다.
  • 디스패치 함수는 액션 객체를 받아 해당 액션을 처리하는 "reducer" 함수를 실행한다. 

 

👉 예시

import React, { useReducer } from "react";

const initalState = { count : 0 };

function reduce(state, action) {
   switch (action.type) {
      case "increment" :
        return { count: state.count + 1};
      case "decrement" :
        return { count: state.count - 1};
      default :
        throw new Error();
   }

}


function Counter() {
   const [state, dispatch] = useReducer(reducer, initialState);
   
   return (
    <>
     Count: {state.count}
     <button onClick={() => dispatch({ type : "increment" })}>+</button> 
     <button onClick={() => dispatch({ type : "decrement" })}>-</button> 
    </>
   );
}

 

2️⃣ 실시간 채팅 기능

📚 HTTP vs WebSocket

👉 HTTP는 단방향 통신 및 요청-응답 프로토콜입니다. 클라이언트(보통 웹 브라우저)는 서버에게 요청을 보내고, 서버는 요청을 처리한 후 응답을 반환한다. 

👉 HTTP는 한 번의 요청과 응답이 완료되면, 연결은 종료됩니다. 따라서 HTTP는 무상태 프로토콜(stateless Protocol)이라고 불리며, 각각의 요청이 독립적으로 처리된다. 

👉 WebSocket은 양방향 통신 프로토콜로, 클라이언트와 서버 간에 지속적인 연결을 유지할 수 있다. 이 지속적인 연결 덕분에, 서버는 클라이언트에게 필요한 데이터를 실시간으로 푸시할 수 있다. 즉 서버는 클라이언트로부터 요청을 받지 않아도 데이터를 보낼 수 있다. 

 

 

👉 WebSocket을 활용한 실시간 채팅 구현

👉 소켓 설치

npm install socket.io
npm install socket.io-client

1️⃣ server.js

const express = require("express");
const http = require("http");
const socketIO = require("socket.io");
const cors = require("cors");

const app = express();
app.use(cors());
const server = http.createServer(app);
const io = socketIO(server, {
  cors: {
    origin: "http://localhost:3000",
    methods: ["GET", "POST"],
  },
});

io.on("connection", (socket) => {
  console.log("새로운 클라이언트가 연결되었습니다.");

  socket.on("messages", (messages) => {
    console.log("새로운 메시지:", messages);
    io.emit("messages", messages);
  });

  // 클라이언트 연결 해제 처리
  socket.on("disconnect", () => {
    console.log("클라이언트가 연결을 해제하였습니다.");
  });
});

server.listen(3001, () => {
  console.log("서버가 3001 포트에서 실행 중입니다.");
});

2️⃣ chat.js

import React, { useState, useEffect } from "react";
import io from "socket.io-client";

const socket = io("http://localhost:3001")

function Chat() {
  const [username, setUsername] = useState("");
  const [chat, setChat] = useState("");
  const [messages, setMessages] = useState([]);

  useEffect(() => {
    socket.on("messages", handleMessage)
    return () => {
      socket.off("messages", handleMessage);
    }
  }, [])

  const handleMessage = (message) => {
    setMessages((prev) => [...prev, message]);
  }

  const handleSubmit = () => {
    if (chat.trim() !== "") {
      const currentTime = new Date().toLocaleDateString();
      socket.emit("messages", {
        username,
        content: chat,
        time: currentTime,
      })
      setChat("");
      setUsername("");
    }
  }

  return (
    <>
     <h1>실시간 채팅</h1>
     <input type="text" value={username} onChange={(e) => setUsername(e.target.value)}/>
     <input type="text" value={chat} onChange={(e) => setChat(e.target.value)}/>
     <div>
      {messages.map((messages, index) => (
        <p key={index}>{messages.username} : {messages.content} - {messages.time}</p>
      ))}
     </div>
     <button onClick={handleSubmit}>전송</button>
    </>
  )

}
export default Chat;

 

 본 후기는 유데미-스나이퍼팩토리 10주 완성 프로젝트캠프 학습 일지 후기로 작성 되었습니다.

728x90