티스토리 뷰
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 |