티스토리 뷰

Edu_hanghae99/TIL

[TIL] 230110

soobin Choi 2023. 1. 11. 01:45

SearchRoom.jsx

수정 전

// 외부 모듈
import React, { useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import styled from 'styled-components';

// 내부 모듈
import { searchRoom } from '../../../../redux/modules/roomSlice';
import search from '../../../../assets/img/search.png';

function SearchRoom() {
  const dispatch = useDispatch();
  const roomList = useSelector((state) => state.rooms.rooms);
  const roomName = roomList.map((room) => room.roomName);
  const [keyword, setKeyword] = useState('');

  function onClickSearchRoom() {
    if (roomName.find((x) => x.includes(keyword))) {
      alert('찾았닭');
      dispatch(searchRoom(keyword));
    } else {
      alert('찾는 방이 없닭');
    }
    setKeyword('');
  }

  return (
    <StSearchRoom>
      <SearchInput
        placeholder="방 제목을 검색하닭"
        value={keyword}
        onChange={(e) => setKeyword(e.target.value)}
      />
      {/* eslint-disable-next-line react/jsx-no-bind */}
      <SearchBtn disabled={!keyword} onClick={onClickSearchRoom}>
        <img src={search} alt="search icon" />
      </SearchBtn>
    </StSearchRoom>
  );
}

const StSearchRoom = styled.div`
  display: flex;
  justify-content: center;
  align-items: center;
  width: 30%;
`;

const SearchInput = styled.input`
  width: 100%;
  height: 30px;
`;

const SearchBtn = styled.button`
  margin-left: 10px;
  border: 0;
  background: none;
  cursor: pointer;
  img {
    width: 30px;
    height: 30px;
  }
`;

export default SearchRoom;

수정된 후

  const dispatch = useDispatch();
  const [keyword, setKeyword] = useState('');

  function onClickSearchRoom() {
    dispatch(searchRoom(keyword));
    setKeyword('');
  }

내가 잘못 쓴 부분

  const roomList = useSelector((state) => state.rooms.rooms);
  const roomName = roomList.map((room) => room.roomName);

다른 컴포넌트에서 store의 rooms를 useSelector로 가져오고 있는데 여기서 또 rooms를 가져오는 바람에 map is not a function 에러가 떴다. 백에서 일부 문자만 넣어도 검색이 되도록 로직을 구현했기 때문에 그냥 keyword만 보내주면 되는 것이었다.

 

CahtBox.jsx

수정 전

import React, { useEffect, useRef, useState } from 'react';
import { useParams } from 'react-router-dom';
import styled from 'styled-components';
import * as SockJs from 'sockjs-client';
import * as StompJs from '@stomp/stompjs';
import { useCookies } from 'react-cookie';
import { getNicknameCookie } from '../../../../utils/cookies';
function ChatBox() {
  const client = useRef({});
  const param = useParams();
  const [cookie] = useCookies();
  const nickname = getNicknameCookie('nickname');
  const [input, setInput] = useState('');
  const [chatMessages, setChatMessages] = useState([]);
  //   console.log(client);
  console.log('param.roomId', param.roomId);
  console.log('nickname', nickname);
  //   console.log('input', input);
  console.log('chatMessage', chatMessages);
  const subscribe = () => {
    console.log(1);
    client.current.subscribe(`/sub/gameroom/${param.roomId}`, ({ body }) => {
      console.log(2);
      setChatMessages((newMessage) => [...newMessage, JSON.parse(body)]);
      console.log(3);
    });
  };
  const connect = () => {
    console.log(4);
    client.current = new StompJs.Client({
      webSocketFactory: () => new SockJs(`http://13.209.84.31:8080/ws-stomp`), // proxy를 통한 접속
      // webSocketFactory: () =>
      //   new SockJs(`${process.env.REACT_APP_API_URL}/ws-stomp`), // proxy를 통한 접속
      connectHeaders: {
        Authorization: cookie.access_token,
        'Refresh-Token': cookie.refresh_token,
      },
      debug(str) {
        console.log('chat str', str);
      },
      onConnect: () => {
        subscribe();
        if (nickname) {
          client.current.publish({
            destination: '/pub/chat/messages',
            body: JSON.stringify({
              type: 'ENTER',
              roomId: param.roomId,
              sender: nickname,
              message: `${nickname}님이 게임에 참가하셨습니다.`,
            }),
          });
          console.log(5);
        }
      },
      onStompError: (frame) => {
        console.log('chat frame', frame);
      },
    });
    client.current.activate();
  };
  const disconnect = () => {
    client.current.deactivate();
  };
  const publish = (input) => {
    if (!client.current.connected) {
      return;
    }
    if (input === '') {
      alert('채팅 내용을 입력해주세요.');
      return;
    }
    client.current.publish({
      destination: '/pub/chat/messages',
      body: JSON.stringify({
        type: 'TALK',
        roomId: param.roomId,
        sender: nickname,
        message: input,
      }),
    });
    setInput('');
  };
  useEffect(() => {
    connect();
    return () => disconnect();
  }, []);
  return (
    <StChatBox>
      <StNotice>공지내용</StNotice>
      <StUserChatBox>
        {chatMessages && chatMessages.length > 0 && (
          <div>
            {chatMessages?.map((newMessage, idx) => {
              if (newMessage.type === 'ENTER') {
                return (
                  <div
                    key={idx}
                    className="anotherChatMessage"
                  >{`${newMessage.message}`}</div>
                );
              }
              if (newMessage.sender === nickname) {
                return (
                  <div
                    key={idx}
                    className="myChatMessage"
                  >{`${newMessage.sender}: ${newMessage.message}`}</div>
                );
              }
              return (
                <div
                  key={idx}
                  className="anotherChatMessage"
                >{`${newMessage.sender}: ${newMessage.message}`}</div>
              );
            })}
          </div>
        )}
      </StUserChatBox>
      <StSendChat>
        <input
          type="text"
          placeholder="채팅을 입력해주세요."
          value={input}
          onChange={(e) => setInput(e.target.value)}
          onKeyPress={(e) => e.key === 'Enter' && publish(input)}
        />
        <button onClick={() => publish(input)}>전송</button>
      </StSendChat>
    </StChatBox>
  );
}
const StChatBox = styled.div`
  border: 2px solid black;
  display: grid;
  grid-template-rows: 50px 1fr 50px;
`;
const StNotice = styled.div`
  border: 1px solid black;
`;
const StUserChatBox = styled.div`
  border: 1px solid black;
`;
const StSendChat = styled.div`
  border: 1px solid black;
  height: 50px;
`;
export default ChatBox;

수정된 후

import React, { useEffect, useRef, useState } from 'react';
import { useParams } from 'react-router-dom';
import styled from 'styled-components';
import * as SockJs from 'sockjs-client';
import * as StompJs from '@stomp/stompjs';
import { useCookies } from 'react-cookie';
import { getNicknameCookie } from '../../../../utils/cookies';

function ChatBox() {
  const client = useRef({});
  const param = useParams();
  const [cookie] = useCookies();
  const nickname = getNicknameCookie('nickname');
  const [message, setMessage] = useState('');
  const [chatMessages, setChatMessages] = useState([]);
  const allMessages = [];
  const connectHeaders = {
    Authorization: cookie.access_token,
    'Refresh-Token': cookie.refresh_token,
  };

  const subscribe = () => {
    client.current.subscribe(
      `/sub/gameroom/${param.roomId}`,
      async ({ body }) => {
        const data = JSON.parse(body);
        console.log('subscribe data', data);
        switch (data.type) {
          case 'ENTER': {
            console.log('enter');
            break;
          }
          case 'CHAT': {
            setChatMessages([...chatMessages, data.message]);
            break;
          }
          default: {
            console.log('default');
            break;
          }
        }
      },
    );
  };
  const connect = () => {
    client.current = new StompJs.Client({
      webSocketFactory: () => new SockJs(`http://13.209.84.31:8080/ws-stomp`),
      connectHeaders,
      debug() {},
      onConnect: () => {
        subscribe();
        client.current.publish({
          destination: `/sub/gameroom/${param.roomId}`,
          body: JSON.stringify({
            type: 'ENTER',
            roomId: param.roomId,
            sender: nickname,
          }),
        });
      },
      onStompError: (frame) => {
        console.log(`Broker reported error: ${frame.headers.message}`);
        console.log(`Additional details: ${frame.body}`);
      },
    });
    client.current.activate();
  };

  function publish(value) {
    client.current.publish({
      destination: `/sub/gameroom/${param.roomId}`,
      body: JSON.stringify({
        type: 'CHAT',
        roomId: param.roomId,
        sender: nickname,
        message: value,
      }),
    });
    setMessage('');
  }

  useEffect(() => {
    connect();
  }, []);
  return (
    <StChatBox>
      <StNotice>공지내용</StNotice>
      <StUserChatBox>
        <div>
          {chatMessages?.map((message) => {
            return <li>{message}</li>;
          })}
        </div>
      </StUserChatBox>
      <StSendChat>
        <input
          type="text"
          placeholder="채팅을 입력해주세요."
          value={message}
          onChange={(e) => setMessage(e.target.value)}
        />
        <button onClick={() => publish(message)}>전송</button>
      </StSendChat>
    </StChatBox>
  );
}
const StChatBox = styled.div`
  border: 2px solid black;
  display: grid;
  grid-template-rows: 50px 1fr 50px;
`;
const StNotice = styled.div`
  border: 1px solid black;
`;
const StUserChatBox = styled.div`
  border: 1px solid black;
`;
const StSendChat = styled.div`
  border: 1px solid black;
  height: 50px;
`;
export default ChatBox;

다 이해하지 못하고 코드를 쓰면 먼 길로 돌아가기만 하는 것 같다.

 

지금은 입력하는 값들만 화면에 보인다.

채팅하는 사람 유저의 닉네임을 보여주어야 하고,

채팅 내역이 순서대로 쌓여야 한다.

+ 채팅방 공지사항도 상단에 보여야 하고, 업데이트해줘야 한다.

 

이제 console 을 찍으면서 머리를 쥐어짜내야 한다.

나는 이틀이나 다른 사람 코드보면서도 끙끙거렸는데 30분 만에 해결됐다...

 

 

https://m.blog.naver.com/toruin84/222461782374

 

'Edu_hanghae99 > TIL' 카테고리의 다른 글

[TIL] 230112  (0) 2023.01.13
[TIL] 230111  (0) 2023.01.11
[TIL] 230109  (0) 2023.01.10
[TIL] 방 검색 230106  (0) 2023.01.07
[TIL] 230105  (0) 2023.01.06