사실상 Slack의 클론코딩은 지난 주 6주차가 마지막이었고, 오늘은 보너스 섹션인데, 찐막이라고 할 수 있겠다... (벌써?)
바로 시작해보장~
1. 이미지 드래그 업로드하기
이미지를 드래그하여 드랍하는 순간 바로 업로드되도록 할 것이다.
핵심 이벤트는
onDragOver : 이미지를 클릭하여 드래그하는 동안에 계속적으로 호출됨
onDrop : 이미지를 드롭하는 순간(드래그에서 손을 떼는 순간) 호출됨
이 두 가지이며, 이 두 가지 이벤트가 설정된 부분을 이미지를 드롭할 수 있는 영역, Drop Zone이라고 한다. (여기서는 Container가 드랍존이 되겠다.)
드랍한 이미지는 items 혹은 files 안에 들어있어 이를 서버로 보내면 업로드가 되는 것인데, 과정을 정리하면 다음과 같다.
1. 브라우저에 따라(?) 이미지가 items에 들어있을 수도, files에 들어있을 수도 있다.
2. 일반적으로 서버로 파일을 보낼 때는 json 형식이 아닌 formData 형식으로 보낸다.
3. 이미지를 여러 개를 한 번에 보낼 수도 있기에 for문을 이용해 items(files)배열을 돌며 아이템을 하나씩 formData에 추가한 뒤, 서버에 post 요청을 보낸다.
+ 요청을 받아온 뒤 revalidate 해주는 것도 잊지말자
풀 코드)
const [ dragOver, setDragOver ] = useState(false);
// ...
const onDrop = useCallback((e) => {
e.preventDefault();
console.log(e);
const formData = new FormData();
if (e.dataTransfer.items) {
for (let i = 0; i < e.dataTransfer.items.length; i++) {
if (e.dataTransfer.items[i].kind === 'file') {
const file = e.dataTransfer.items[i].getAsFile();
console.log(e, '.... file[' + i + '].name = ' + file.name);
formData.append('image', file);
}
}
} else {
for (let i = 0; i < e.dataTransfer.files.length; i++) {
console.log(e, '... file[' + i + '].name = ' + e.dataTransfer.files[i].name);
formData.append('image', e.dataTransfer.files[i]);
}
}
axios.post(`/api/workspaces/${workspace}/channels/${channel}/images`, formData).then(() => {
setDragOver(false);
revalidate();
});
},
[workspace, channel],
);
const onDragOver = useCallback((e) => {
e.preventDefault();
console.log(e);
setDragOver(true);
}, []);
// ...
return (
<Container onDrop={onDrop} onDragOver={onDragOver}>
<Header>
<img src={gravatar.url(userData.email, { s: '24px', d: 'retro' })} alt={userData.nickname} />
<span>{useData.nickname}</span>
</Header>
<ChatList chatSections={chatSections} ref={scrollbarRef} setSize={setSize} isReachingEnd={isReachingEnd} />
<ChatBox chat={chat} onChangeChat={onChangeChat} onSubmitForm={onSubmitForm} />
{dragOver && <DragOver>업로드!</DragOver>}
</Container>
)
2. 안 읽은 메시지 개수 표시하기
안 읽은 메시지의 개수를 알려면 우선
1. 내가 어디까지 읽었는지
2. 얼마나 쌓여있는지
를 알아야겠져?
1 -> 내가 확인한 시점을 그때그때 저장하며 업데이트해주어야 한다. 이때, DB보다는 브라우저의 localStorage에 저장하는 것을 권장한다.
useEffect(() => {
localStorage.setItem(`${workspace}-${channel}`, new Date().getTime().toString());
}, [workspace, channel]);
읽은 시간말고도 만약 내가 채팅을 치거나 이미지를 업로드 했다면, 그 시간도 기록을 해주어야 한다는 점을 유의하자.
2 -> 타임스탬프로 찍어 놓은 시간을 넣어놓고, 그 시간 이후로 쌓인 메시지의 개수를 서버에서 받아온다.
const EachChannel: VFC<Props> = ({ channel }) => {
const { workspace } = useParams<{ workspace?: string }>();
const location = useLocation();
const { data: userData } = useSWR<IUser>('/api/users', fetcher, {
dedupingInterval: 2000,
});
const date = localStorage.getItem(`${workspace}-${channel.name}`) || 0;
const { data: count, mutate } = useSWR<number>(
userData ? `/api/workspaces/${workspace}/channels/${channel.name}/unreads?after=${date}` : null,
fetcher,
);
정리하면, 내가 채널이든 디엠이든 언제 들어갔었는지 그 시간을 저장하고, 그 시간으로부터 쌓인 메시지를 api를 통해 받아오면 된다.
3. SWR Devtools
SWR 사용 시 디버깅하기에 좀 더 편리하도록 도와주는 툴이다.
npm i @jjordy/swr-devtools
설치 후,
import SWRDevtools from '@jjordy/swr-devtools';
import { cache, mutate } from 'swr';
// ...
render(
<BrowserRouter>
<>
<SWRDevtools cache={cache} mutate={mutate} /> // 추가
<App />
</>
</BrowserRouter>,
document.querySelector('#app'),
);
가장 최상단 컴포넌트 쪽에 표시한 한 줄을 추가하여 설정해준다.

npm run dev를 해보면 이렇게 SWR을 사용한 부분에 대해 데이터를 확인할 수 있다.
슬리액 강의를 들으면서 SWR을 사용하여 전역 상태 관리를 해주었는데, 안그래도 배운걸 적용해보려고 하던 찰나에 이런 유용한 툴까지 알려주셔서 같이 한 번 사용해보면 더 좋을 것 같다.
배운건 꼭 써먹어버릇하자 ,,
이건 오늘 강의뿐 아니라 전반적으로 다 해당되는 이야기
아자아자 화이팅
아 그리고 이건 강의 보다가 제로초 선생님께서 같은 단어를 여러 개 선택해서 한번에 바꾸는게 편해보여서... 안그래도 전부터 단축키가 뭘까 궁금했는데 잊고 있다가 찾아보게 되어서, 링크 달아봄. Ctrl+D 쓰면 된다네여
[VSCode] 다중 선택 - 같은 단어(변수) 모두 선택하여 수정하는 2가지 방법
VSCode에서 좀 더 편리하게 코드를 수정하는 방법을 알아보고 있습니다. [VSCode] 다중 커서 - 여러줄 선택 하는 2가지 방법 (세로 선택) [VSCode] 다중 선택 - 커서를 여러개 추가하기 VSCode는 같은 단어
hianna.tistory.com
'프론트엔드 > React' 카테고리의 다른 글
[React] 리액트 생명주기와 Effect Hook (useEffect, useLayoutEffect, useInsertionEffect) (0) | 2024.08.05 |
---|---|
[React/TS] Slack 클론코딩 6주차 - 마무리하기 (1) | 2023.11.26 |
[React/TS] Slack 클론코딩 5주차 - 실시간 채팅, 각종 프론트 기술 배우기 (0) | 2023.11.19 |
Redux(리덕스)란? 상태 관리 도구 리덕스에 대해 알아보자 (0) | 2023.11.07 |
[React/TS] Slack 클론코딩 3주차, 4주차 (1) | 2023.11.05 |
사실상 Slack의 클론코딩은 지난 주 6주차가 마지막이었고, 오늘은 보너스 섹션인데, 찐막이라고 할 수 있겠다... (벌써?)
바로 시작해보장~
1. 이미지 드래그 업로드하기
이미지를 드래그하여 드랍하는 순간 바로 업로드되도록 할 것이다.
핵심 이벤트는
onDragOver : 이미지를 클릭하여 드래그하는 동안에 계속적으로 호출됨
onDrop : 이미지를 드롭하는 순간(드래그에서 손을 떼는 순간) 호출됨
이 두 가지이며, 이 두 가지 이벤트가 설정된 부분을 이미지를 드롭할 수 있는 영역, Drop Zone이라고 한다. (여기서는 Container가 드랍존이 되겠다.)
드랍한 이미지는 items 혹은 files 안에 들어있어 이를 서버로 보내면 업로드가 되는 것인데, 과정을 정리하면 다음과 같다.
1. 브라우저에 따라(?) 이미지가 items에 들어있을 수도, files에 들어있을 수도 있다.
2. 일반적으로 서버로 파일을 보낼 때는 json 형식이 아닌 formData 형식으로 보낸다.
3. 이미지를 여러 개를 한 번에 보낼 수도 있기에 for문을 이용해 items(files)배열을 돌며 아이템을 하나씩 formData에 추가한 뒤, 서버에 post 요청을 보낸다.
+ 요청을 받아온 뒤 revalidate 해주는 것도 잊지말자
풀 코드)
const [ dragOver, setDragOver ] = useState(false);
// ...
const onDrop = useCallback((e) => {
e.preventDefault();
console.log(e);
const formData = new FormData();
if (e.dataTransfer.items) {
for (let i = 0; i < e.dataTransfer.items.length; i++) {
if (e.dataTransfer.items[i].kind === 'file') {
const file = e.dataTransfer.items[i].getAsFile();
console.log(e, '.... file[' + i + '].name = ' + file.name);
formData.append('image', file);
}
}
} else {
for (let i = 0; i < e.dataTransfer.files.length; i++) {
console.log(e, '... file[' + i + '].name = ' + e.dataTransfer.files[i].name);
formData.append('image', e.dataTransfer.files[i]);
}
}
axios.post(`/api/workspaces/${workspace}/channels/${channel}/images`, formData).then(() => {
setDragOver(false);
revalidate();
});
},
[workspace, channel],
);
const onDragOver = useCallback((e) => {
e.preventDefault();
console.log(e);
setDragOver(true);
}, []);
// ...
return (
<Container onDrop={onDrop} onDragOver={onDragOver}>
<Header>
<img src={gravatar.url(userData.email, { s: '24px', d: 'retro' })} alt={userData.nickname} />
<span>{useData.nickname}</span>
</Header>
<ChatList chatSections={chatSections} ref={scrollbarRef} setSize={setSize} isReachingEnd={isReachingEnd} />
<ChatBox chat={chat} onChangeChat={onChangeChat} onSubmitForm={onSubmitForm} />
{dragOver && <DragOver>업로드!</DragOver>}
</Container>
)
2. 안 읽은 메시지 개수 표시하기
안 읽은 메시지의 개수를 알려면 우선
1. 내가 어디까지 읽었는지
2. 얼마나 쌓여있는지
를 알아야겠져?
1 -> 내가 확인한 시점을 그때그때 저장하며 업데이트해주어야 한다. 이때, DB보다는 브라우저의 localStorage에 저장하는 것을 권장한다.
useEffect(() => {
localStorage.setItem(`${workspace}-${channel}`, new Date().getTime().toString());
}, [workspace, channel]);
읽은 시간말고도 만약 내가 채팅을 치거나 이미지를 업로드 했다면, 그 시간도 기록을 해주어야 한다는 점을 유의하자.
2 -> 타임스탬프로 찍어 놓은 시간을 넣어놓고, 그 시간 이후로 쌓인 메시지의 개수를 서버에서 받아온다.
const EachChannel: VFC<Props> = ({ channel }) => {
const { workspace } = useParams<{ workspace?: string }>();
const location = useLocation();
const { data: userData } = useSWR<IUser>('/api/users', fetcher, {
dedupingInterval: 2000,
});
const date = localStorage.getItem(`${workspace}-${channel.name}`) || 0;
const { data: count, mutate } = useSWR<number>(
userData ? `/api/workspaces/${workspace}/channels/${channel.name}/unreads?after=${date}` : null,
fetcher,
);
정리하면, 내가 채널이든 디엠이든 언제 들어갔었는지 그 시간을 저장하고, 그 시간으로부터 쌓인 메시지를 api를 통해 받아오면 된다.
3. SWR Devtools
SWR 사용 시 디버깅하기에 좀 더 편리하도록 도와주는 툴이다.
npm i @jjordy/swr-devtools
설치 후,
import SWRDevtools from '@jjordy/swr-devtools';
import { cache, mutate } from 'swr';
// ...
render(
<BrowserRouter>
<>
<SWRDevtools cache={cache} mutate={mutate} /> // 추가
<App />
</>
</BrowserRouter>,
document.querySelector('#app'),
);
가장 최상단 컴포넌트 쪽에 표시한 한 줄을 추가하여 설정해준다.

npm run dev를 해보면 이렇게 SWR을 사용한 부분에 대해 데이터를 확인할 수 있다.
슬리액 강의를 들으면서 SWR을 사용하여 전역 상태 관리를 해주었는데, 안그래도 배운걸 적용해보려고 하던 찰나에 이런 유용한 툴까지 알려주셔서 같이 한 번 사용해보면 더 좋을 것 같다.
배운건 꼭 써먹어버릇하자 ,,
이건 오늘 강의뿐 아니라 전반적으로 다 해당되는 이야기
아자아자 화이팅
아 그리고 이건 강의 보다가 제로초 선생님께서 같은 단어를 여러 개 선택해서 한번에 바꾸는게 편해보여서... 안그래도 전부터 단축키가 뭘까 궁금했는데 잊고 있다가 찾아보게 되어서, 링크 달아봄. Ctrl+D 쓰면 된다네여
[VSCode] 다중 선택 - 같은 단어(변수) 모두 선택하여 수정하는 2가지 방법
VSCode에서 좀 더 편리하게 코드를 수정하는 방법을 알아보고 있습니다. [VSCode] 다중 커서 - 여러줄 선택 하는 2가지 방법 (세로 선택) [VSCode] 다중 선택 - 커서를 여러개 추가하기 VSCode는 같은 단어
hianna.tistory.com
'프론트엔드 > React' 카테고리의 다른 글
[React] 리액트 생명주기와 Effect Hook (useEffect, useLayoutEffect, useInsertionEffect) (0) | 2024.08.05 |
---|---|
[React/TS] Slack 클론코딩 6주차 - 마무리하기 (1) | 2023.11.26 |
[React/TS] Slack 클론코딩 5주차 - 실시간 채팅, 각종 프론트 기술 배우기 (0) | 2023.11.19 |
Redux(리덕스)란? 상태 관리 도구 리덕스에 대해 알아보자 (0) | 2023.11.07 |
[React/TS] Slack 클론코딩 3주차, 4주차 (1) | 2023.11.05 |