작성자 없음
작성자 정보가 삭제된 글입니다.
작성
·
496
0
const onSubmitForm = useCallback(
// optimistic UI
(e: any) => {
e.preventDefault();
console.log(chat);
if (chat?.trim() && chatData) {
const savedChat = chat;
mutateChat((prevChatData) => {
prevChatData?.[0].unshift({
id: (chatData[0][0]?.id || 0) + 1,
content: savedChat,
SenderId: myData.id,
Sender: myData,
ReceiverId: userData.id,
Receiver: userData,
createdAt: new Date(),
});
return prevChatData;
// 먼저 추가해서 보여주고 post요청.
}, false).then(() => {
setChat('');
scrollbarRef.current?.scrollToBottom();
});
axios
.post(`/api/workspaces/${workspace}/dms/${id}/chats`, {
content: chat,
})
.then(() => {
mutateChat();
})
.catch(console.error);
}
},
[chat, chatData, myData, userData, workspace, id],
);
date쓰는곳이 onSubmit함수 안인데..
왜이럴까요...ㅜ
답변 2
0
메시지 부분은 chat 을 말씀하시는걸까요? ㅠ
data.createdAt을 주석처리했더니 에러가 바뀌긴 했어요
근데 에러가 어디서 나는지 알기가 어렵네요..
import React, { memo, useMemo, VFC } from 'react';
import { ChatWrapper } from './styles';
import gravatar from 'gravatar';
import regexifyString from 'regexify-string';
import { Link, useParams } from 'react-router-dom';
interface Props {
data: any;
}
// a?.b optional chaining
// a??b nullish coalescing
const Chat: VFC<Props> = ({ data }) => {
const user = data.Sender;
const { workspace } = useParams<{ workspace: string; channel: string }>();
const result = useMemo(
() =>
regexifyString({
input: data.content,
pattern: /@\[(.+?)]\((\d+?)\)|\n/g,
decorator(match, index) {
const arr: string[] | null = match.match(/@\[(.+?)]\((\d+?)\)/)!;
if (arr) {
return (
<Link key={match + index} to={`/workspace/${workspace}/dm/${arr[2]}`}>
@{arr[1]}
</Link>
);
}
return <br key={index} />;
},
}),
[data.content],
);
return (
<ChatWrapper>
<div className="chat-img">
<img src={gravatar.url(user.email, { s: '36px', d: 'retro' })} alt={user.nickname} />
</div>
<div className="chat-text">
<div className="chat-user">
<b>{user.nickname}</b>
{/* <span>{data.createdAt}</span> */}
</div>
<p>{result}</p>
</div>
</ChatWrapper>
);
};
export default memo(Chat);
import Chat from '@components/chat';
import { ChatZone, Section, StickyHeader } from '@components/chatList/styles';
import { IChat, IDM } from '@typings/db';
import React, { useCallback, forwardRef, ForwardedRef, RefObject, VFC } from 'react';
import { Scrollbars } from 'react-custom-scrollbars';
interface Props {
chatSections: { [key: string]: IDM[] };
setSize: (f: (size: number) => number) => Promise<(IDM | IChat)[][] | undefined>;
isReachingEnd: boolean;
scrollRef: RefObject<Scrollbars>;
}
const ChatList: VFC<Props> = ({ chatSections, setSize, scrollRef, isReachingEnd }) => {
const onScroll = useCallback(
(values: any) => {
if (values.scrollTop === 0 && !isReachingEnd) {
console.log('가장 위');
setSize((prevSize) => prevSize + 1).then(() => {
// 스크롤 위치 유지
if (scrollRef?.current) {
scrollRef.current?.scrollTop(scrollRef.current?.getScrollHeight() - values.scrollHeight);
}
});
}
},
[scrollRef, isReachingEnd, setSize],
);
return (
<ChatZone>
<Scrollbars autoHide ref={scrollRef} onScrollFrame={onScroll}>
{Object.entries(chatSections).map(([date, chats]) => {
return (
<Section className={`section-${date}`} key={date}>
<StickyHeader>
<button>{date}</button>
</StickyHeader>
{chats.map((chat) => (
<Chat key={chat.id} data={chat} />
))}
</Section>
);
})}
</Scrollbars>
</ChatZone>
);
};
export default ChatList;
import ChatBox from '@components/chatBox';
import ChatList from '@components/chatList';
import useInput from '@hooks/useInput';
import useSocket from '@hooks/useSocket';
import { Container, DragOver, Header } from '@pages/directMessage/styles';
import { IDM } from '@typings/db';
import fetcher from '@utils/fetcher';
import makeSection from '@utils/makeSection';
import axios from 'axios';
import React, { useCallback, useEffect, useRef, useState } from 'react';
import gravatar from 'gravatar';
import Scrollbars from 'react-custom-scrollbars';
import { useParams } from 'react-router-dom';
import useSWR from 'swr';
import useSWRInfinite from 'swr/infinite';
import Workspace from '@layouts/workspace';
const DirectMessage = () => {
const { workspace, id } = useParams<{ workspace: string; id: string }>();
console.log(id, 'id');
const { data: userData } = useSWR(`/api/workspaces/${workspace}/users/${id}`, fetcher);
const { data: myData } = useSWR('/api/users', fetcher);
const [chat, onChangeChat, setChat] = useInput('');
const {
data: chatData,
mutate: mutateChat,
setSize,
} = useSWRInfinite<IDM[]>(
(index) => `/api/workspaces/${workspace}/dms/${id}/chats?perPage=20&page=${index + 1}`,
fetcher,
);
const [socket] = useSocket(workspace);
const isEmpty = chatData?.[0]?.length === 0;
const isReachingEnd = isEmpty || (chatData && chatData[chatData.length - 1]?.length < 20) || false;
const scrollbarRef = useRef<Scrollbars>(null);
const [dragOver, setDragOver] = useState(false);
const onSubmitForm = useCallback(
(e: any) => {
e.preventDefault();
console.log(chat);
if (chat?.trim() && chatData) {
const savedChat = chat;
mutateChat((prevChatData) => {
prevChatData?.[0].unshift({
id: (chatData[0][0]?.id || 0) + 1,
content: savedChat,
SenderId: myData.id,
Sender: myData,
ReceiverId: userData.id,
Receiver: userData,
createdAt: new Date(),
});
return prevChatData;
}, false).then(() => {
setChat('');
scrollbarRef.current?.scrollToBottom();
});
axios
.post(`/api/workspaces/${workspace}/dms/${id}/chats`, {
content: chat,
})
.then(() => {
mutateChat();
})
.catch(console.error);
}
},
[chat, chatData, myData, userData, workspace, id],
);
const onMessage = useCallback((data: IDM) => {
// id는 상대방 아이디
if (data.SenderId === Number(id) && myData.id !== Number(id)) {
mutateChat((chatData) => {
chatData?.[0].unshift(data);
return chatData;
}, false).then(() => {
if (scrollbarRef.current) {
if (
scrollbarRef.current.getScrollHeight() <
scrollbarRef.current.getClientHeight() + scrollbarRef.current.getScrollTop() + 150
) {
console.log('scrollToBottom!', scrollbarRef.current?.getValues());
setTimeout(() => {
scrollbarRef.current?.scrollToBottom();
}, 50);
}
}
});
}
}, []);
useEffect(() => {
socket?.on('dm', onMessage);
return () => {
socket?.off('dm', onMessage);
};
}, [socket, onMessage]);
// 로딩 시 스크롤바 제일 아래로
useEffect(() => {
if (chatData?.length === 1) {
setTimeout(() => {
scrollbarRef.current?.scrollToBottom();
}, 100);
}
}, [chatData]);
const onDrop = useCallback(
(e: any) => {
e.preventDefault();
console.log(e);
const formData = new FormData();
if (e.dataTransfer.items) {
// Use DataTransferItemList interface to access the file(s)
for (let i = 0; i < e.dataTransfer.items.length; i++) {
// If dropped items aren't files, reject them
if (e.dataTransfer.items[i].kind === 'file') {
const file = e.dataTransfer.items[i].getAsFile();
console.log('... file[' + i + '].name = ' + file.name);
formData.append('image', file);
}
}
} else {
// Use DataTransfer interface to access the file(s)
for (let i = 0; i < e.dataTransfer.files.length; i++) {
console.log('... file[' + i + '].name = ' + e.dataTransfer.files[i].name);
formData.append('image', e.dataTransfer.files[i]);
}
}
axios.post(`/api/workspaces/${workspace}/dms/${id}/images`, formData).then(() => {
setDragOver(false);
mutateChat();
});
},
[mutateChat, workspace, id],
);
const onDragOver = useCallback((e: any) => {
e.preventDefault();
console.log(e);
setDragOver(true);
}, []);
if (!userData || !myData) {
return null;
}
const chatSections = makeSection(chatData ? chatData.flat().reverse() : []);
return (
<Workspace>
<Container onDrop={onDrop} onDragOver={onDragOver}>
<Header>
<img src={gravatar.url(userData.email, { s: '24px', d: 'retro' })} alt={userData.nickname} />
<span>{userData.nickname}</span>
</Header>
<ChatList
chatSections={chatSections}
scrollRef={scrollbarRef}
setSize={setSize}
isReachingEnd={isReachingEnd}
/>
<ChatBox chat={chat} onChangeChat={onChangeChat} onSubmitForm={onSubmitForm} />
{dragOver && <DragOver>업로드!</DragOver>}
</Container>
</Workspace>
);
};
export default DirectMessage;
0
에러의 위치는 에러메시지에 친절하게 줄 수까지 나와 있습니다.
또는 콘솔창에도 에러 줄이 있을 겁니다. 어디의 id를 가리키는지 확인해보세요. 코드 상으로는 myData나 userData가 undefined일 겁니다. 왜 undefined인지 분석해보세요.