티스토리 뷰
[Error] Each child in a list should have a unique "key" prop.
https://crong-dev.tistory.com/47
너무 간단하게 해결됨.!
수정 전
map 돌릴 때 고유한 key 값이 없으면 위의 에러 발생
<StUserChatBox>
<div>
{chatMessages?.map((message) => {
return <li>{message}</li>;
})}
</div>
</StUserChatBox>
수정 후
<StUserChatBox>
<div>
{chatMessages?.map((message) => {
return <li key={message}>{message}</li>;
})}
</div>
</StUserChatBox>
수정 중 1차
<StUserChatBox>
{chatData.sender && (
<div>
{chatMessages?.map((message) => {
// 채팅 내역들
if (chatData.type === 'CHAT') {
return (
<Chats key={message}>{`채팅들 : ${chatMessages}`}</Chats>
);
}
// 내가 채팅 보내는 경우
if (chatData.sender === nickname) {
return (
<MyChat
key={nickname}
>{`${chatData.sender}: ${chatData.message}`}</MyChat>
);
}
// 다른 사람이 채팅 보내는 경우
return (
<AnotherChat
key={nickname}
>{`${chatData.sender}: ${chatData.message}`}</AnotherChat>
);
})}
</div>
)}
</StUserChatBox>
수정 중 2차
<StUserChatBox>
{chatData.sender && chatData.sender === nickname && (
<div>
{chatMessages?.map((nickname) => {
// 내가 채팅 보내는 경우
return (
<MyChat
key={nickname}
>{`${chatData.sender}: ${chatData.message}`}</MyChat>
);
})}
</div>
)}
{chatData.sender && chatData.sender !== nickname && (
<div>
{chatMessages?.map((nickname) => {
// 다른 사람이 채팅 보내는 경우
return (
<AnotherChat
key={nickname}
>{`${chatData.sender}: ${chatData.message}`}</AnotherChat>
);
})}
</div>
)}
{/* // 채팅 내역들
if (chatData.type === 'CHAT') {
return (
<Chats key={message}>{`채팅들 : ${chatMessages}`}</Chats>
);
} */}
</StUserChatBox>
채팅들이 배열에 추가 안 됨
2개의 요소가 들어간 배열이 만들어짐
하나는 제일 처음 채팅 나머지는 입력하는 채팅
채팅 리스트 배열 수정 후
setChatMessages((chatMessages) => [...chatMessages, data.message]);
이렇게 바꾸니 새로운 메시지를 입력할 때마다 배열에 데이터가 잘 들어갔다.
수정 3차
<StUserChatBox>
{chatData.sender && (
<div>
<Chats>{`${chatData.sender}: ${chatMessages}`}</Chats>
{chatData.sender === nickname && (
<div>
{chatMessages?.map((nickname) => {
// 내가 채팅 보내는 경우
return (
<MyChat
key={nickname}
>{`${chatData.sender}: ${chatData.message}`}</MyChat>
);
})}
</div>
)}
{chatData.sender !== nickname && (
<div>
{chatMessages?.map((nickname) => {
// 다른 사람이 채팅 보내는 경우
return (
<AnotherChat
key={nickname}
>{`${chatData.sender}: ${chatData.message}`}</AnotherChat>
);
})}
</div>
)}
</div>
)}
</StUserChatBox>
수정 4차
<StUserChatBox>
{chatData.sender && (
<div>
<Chats>{`${chatData.sender}: ${chatMessages}`}</Chats>
{chatData.sender === nickname && (
<MyChat>{`${chatData.sender}: ${chatData.message}`}</MyChat>
)}
{chatData.sender !== nickname && (
<AnotherChat>{`${chatData.sender}: ${chatData.message}`}</AnotherChat>
)}
</div>
)}
</StUserChatBox>
다른 사람이 보낸 메시지면 빨간색, 내가 보낸 메시지면 파란색으로 보임
보라색은 누적되는 쌓이는 채팅 메시지들
문제 : 보라색 유저 네임이 채팅을 입력할 때마다 계속 바뀜.
어떻게 해결해야 할까? 실시간 유저 네임은 유저들이 채팅을 입력할 때마다 보여줘야 하고, 쌓이는 채팅 메시지들에는 누가 어떤 메시지를 썼는지 알 수 있어야 하므로, 채팅 메시지들을 배열로 뿌려준 것처럼 누적 유저 네임을 배열로 만들고 메시지와 함께 보여줘야겠다.
또 수정
const [chatUser, setChatUser] = useState([]); // 누적 유저 이름들
...
case 'CHAT': {
// console.log('chat', data.sender);
setChatMessages((chatMessages) => [...chatMessages, data.message]);
setChatUser((chatUser) => [...chatUser, data.sender]);
break;
}
...
<StUserChatBox>
{chatData.sender && (
<div>
{chatMessages?.map((message, index) => {
return (
<Chats>
<li
key={message}
>{`${chatUser[index]}: ${chatMessages[index]}`}</li>
</Chats>
);
})}
{chatData.sender === nickname && (
<MyChat>{`${chatData.sender}: ${chatData.message}`}</MyChat>
)}
{chatData.sender !== nickname && (
<AnotherChat>{`${chatData.sender}: ${chatData.message}`}</AnotherChat>
)}
</div>
)}
</StUserChatBox>
다시 마주한 에러
[Error] Each child in a list should have a unique "key" prop.
잘 작동하지만 에러를 해결해야 함
고유한 key 값 주기
<StUserChatBox>
{chatData.sender && (
<div>
{chatMessages?.map((message, index) => {
return (
<Chats key={String(index)}>
<div>{`${chatUser[index]}: ${message}`}</div>
</Chats>
);
})}
{chatData.sender === nickname && (
<MyChat>{`${chatData.sender}: ${chatData.message}`}</MyChat>
)}
{chatData.sender !== nickname && (
<AnotherChat>{`${chatData.sender}: ${chatData.message}`}</AnotherChat>
)}
</div>
)}
</StUserChatBox>
key={String(index)}
내가 쓴 채팅은 채팅방 오른쪽 다른 사람 채팅은 채팅방 왼쪽으로 보내고 싶음
{chatData.sender && (
<div>
{chatMessages?.map((message, index) => {
if (chatData.sender === nickname) {
return (
<MyChat
// eslint-disable-next-line react/no-array-index-key
key={String(index)}
>{`${chatUser[index]}: ${message}`}</MyChat>
);
}
return (
<AnotherChat
// eslint-disable-next-line react/no-array-index-key
key={String(index)}
>{`${chatUser[index]}: ${message}`}</AnotherChat>
);
// return (
// <Chat
// // eslint-disable-next-line react/no-array-index-key
// key={String(index)}
// classname={chatData.sender === nickname ? 'my' : ''}
// >
// <div>{`${chatUser[index]}: ${message}`}</div>
// </Chat>
// );
})}
{/* {chatData.sender === nickname && (
<MyChat>{`${chatData.sender}: ${chatData.message}`}</MyChat>
)}
{chatData.sender !== nickname && (
<AnotherChat>{`${chatData.sender}: ${chatData.message}`}</AnotherChat>
)} */}
</div>
)}
그 사이에 많은 삽질을 했고 3시쯤 완성됐다.
채팅 구현 전체 코드
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(''); // input value 값
const [chatMessages, setChatMessages] = useState([]); // 누적 채팅 메시지들
const [chatUser, setChatUser] = useState([]); // 누적 유저 이름들
const connectHeaders = {
Authorization: cookie.access_token,
'Refresh-Token': cookie.refresh_token,
};
const subscribe = async () => {
client.current.subscribe(`/sub/gameroom/${param.roomId}`, ({ body }) => {
const data = JSON.parse(body);
// console.log('subscribe data', data);
switch (data.type) {
case 'ENTER': {
// console.log('enter');
break;
}
case 'CHAT': {
// console.log('chat', data.sender)
setChatMessages((chatMessages) => [...chatMessages, data]);
setChatUser((chatUser) => [...chatUser, data.sender]);
// setChatMessages([...chatMessages, data.message]);
// setChatUser([...chatUser, data.sender]);
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,
message: `${nickname}님이 게임에 참가하셨습니다.`,
}),
});
},
onStompError: (frame) => {
console.log(`Broker reported error: ${frame.headers.message}`);
console.log(`Additional details: ${frame.body}`);
},
});
client.current.activate();
};
// input value 즉 메시지 채팅을 입력
function publish(value) {
if (message === '') {
alert('채팅 내용을 입력해주세요.');
return;
}
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, index) => {
return (
<Chat
// eslint-disable-next-line react/no-array-index-key
key={String(index)}
className={message.sender === nickname ? 'my' : 'other'}
>
<div>{`${message.sender}: ${message.message}`}</div>
</Chat>
);
})}
</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;
`;
const Chat = styled.div`
&.my {
text-align: right;
color: blue;
}
&.other {
color: purple;
text-align: left;
}
`;
export default ChatBox;
공지도 추가해야 하고 더 수정해야 할 듯
'Edu_hanghae99 > TIL' 카테고리의 다른 글
[TIL] 230113 (1) | 2023.01.13 |
---|---|
[TIL] 230112 (0) | 2023.01.13 |
[TIL] 230110 (1) | 2023.01.11 |
[TIL] 230109 (0) | 2023.01.10 |
[TIL] 방 검색 230106 (0) | 2023.01.07 |