Skip to content

Commit b1f601e

Browse files
authored
Refactor/#142-S : 소켓 Context 생성 (#143)
## 🤠 개요 - resolve #142 ## 💫 설명 - #139 를 구현하다가 mom 소켓을 다른 컴포넌트에서도 사용할 일이 있었어요 - ConfButton에서 mom 소켓에 회의 시작과 종료를 알려야 해요 - mom 소켓은 현재 `Editor`에서도 필요해요. 하지만 `Editor`와 `ConfButton`의 거리가 좀 멀어요.. props로 넘겨주기는 몇 단계를 거쳐야 하고, `ConfButton` 안에서 `io(URL)`로 다시 mom 소켓 커넥션을 만들고 싶지도 않았어요 - 그래서 SocketContext를 만들어서 하나의 인스턴스로 관리하도록 했어요 - 어짜피 회의록 소켓 커넥션을 워크스페이스 페이지 내에서 항상 열려있으니까 WorkspacePage에서 소켓을 생성해서 Context를 정의해주었어요. 그리곤 Editor와 ConfButton에서 가져다 사용했어요 - #144 `ConfButton` 개발 내용은 이 안에 있어요. 지금 PR 작업과 겹치는 파일들이 있어서 저 안에 들어간 것도 있어요.. - 참고 자료 [https://itnext.io/how-to-use-a-single-instance-of-socket-io-in-your-react-app-6a4465dcb398](https://itnext.io/how-to-use-a-single-instance-of-socket-io-in-your-react-app-6a4465dcb398) ## 🌜 고민거리 (Optional) ### Q.1 signalingSocket도 context안에서 하나로만 사용할 수 있도록 하고 싶었는데, 현재 WorkspacePage에서 momSocket을 미리 생성해주고 Context를 정의했는데, 시그널링 같은 경우는 아예 ConfMediaBar가 열리면 커넥션이 맺어지게 하려고 했어서 함께 관리하지는 못했어요 ## 📷 스크린샷 (Optional)
1 parent e77feab commit b1f601e

File tree

24 files changed

+259
-53
lines changed

24 files changed

+259
-53
lines changed

client/src/components/ConfMediaBar/ConfMedia/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useEffect, useRef } from 'react';
1+
import { memo, useEffect, useRef } from 'react';
22

33
import style from './style.module.scss';
44

@@ -17,4 +17,4 @@ function ConfMedia({ stream }: MediaProps) {
1717
return <video className={style.video} ref={ref} autoPlay />;
1818
}
1919

20-
export default ConfMedia;
20+
export default memo(ConfMedia);
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { MdVideocam } from '@react-icons/all-files/md/MdVideocam';
2+
import { MdVideocamOff } from '@react-icons/all-files/md/MdVideocamOff';
3+
import { Dispatch, SetStateAction } from 'react';
4+
import color from 'styles/color.module.scss';
5+
6+
interface CamButtonProps {
7+
isOn: boolean;
8+
setIsCamOn?: Dispatch<SetStateAction<boolean>>;
9+
}
10+
11+
function CamButton({ isOn, setIsCamOn }: CamButtonProps) {
12+
const onClick = () => {
13+
if (setIsCamOn) setIsCamOn(!isOn);
14+
};
15+
16+
return (
17+
<button onClick={onClick}>
18+
{isOn ? (
19+
<MdVideocamOff color={color.red} size={20} />
20+
) : (
21+
<MdVideocam color={color.green} size={20} />
22+
)}
23+
</button>
24+
);
25+
}
26+
27+
export default CamButton;
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { MdMic } from '@react-icons/all-files/md/MdMic';
2+
import { MdMicOff } from '@react-icons/all-files/md/MdMicOff';
3+
import { Dispatch, SetStateAction } from 'react';
4+
import color from 'styles/color.module.scss';
5+
6+
interface MicButtonProps {
7+
isOn: boolean;
8+
setIsMicOn?: Dispatch<SetStateAction<boolean>>;
9+
}
10+
11+
function MicButton({ isOn, setIsMicOn }: MicButtonProps) {
12+
const onClick = () => {
13+
if (setIsMicOn) setIsMicOn(!isOn);
14+
};
15+
16+
return (
17+
<button onClick={onClick}>
18+
{isOn ? (
19+
<MdMicOff color={color.red} size={20} />
20+
) : (
21+
<MdMic color={color.green} size={20} />
22+
)}
23+
</button>
24+
);
25+
}
26+
27+
export default MicButton;
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { Dispatch, memo, SetStateAction } from 'react';
2+
3+
import CamButton from './CamButton';
4+
import MicButton from './MicButton';
5+
import style from './style.module.scss';
6+
7+
interface StreamButtonProps {
8+
isMicOn: boolean;
9+
isCamOn: boolean;
10+
setIsMicOn?: Dispatch<SetStateAction<boolean>>;
11+
setIsCamOn?: Dispatch<SetStateAction<boolean>>;
12+
}
13+
14+
function StreamButton({
15+
isMicOn,
16+
isCamOn,
17+
setIsMicOn,
18+
setIsCamOn,
19+
}: StreamButtonProps) {
20+
return (
21+
<div className={style['stream-button']}>
22+
<MicButton isOn={isMicOn} setIsMicOn={setIsMicOn} />
23+
<CamButton isOn={isCamOn} setIsCamOn={setIsCamOn} />
24+
</div>
25+
);
26+
}
27+
28+
export default memo(StreamButton);
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
@import 'styles/color.module';
2+
3+
.stream-button {
4+
display: flex;
5+
align-items: center;
6+
width: fit-content;
7+
margin: auto;
8+
padding: 5px 10px;
9+
border-radius: 20px;
10+
background-color: $gray-300-transparent;
11+
cursor: pointer;
12+
}

client/src/components/ConfMediaBar/index.tsx

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,41 @@
1-
import { io } from 'socket.io-client';
2-
import env from 'src/config';
1+
import { useState } from 'react';
2+
import { useParams } from 'react-router-dom';
33
import { useConfMediaStreams } from 'src/hooks/useConfMediaStreams';
4+
import useSocket from 'src/hooks/useSocket';
45

56
import ConfMedia from './ConfMedia';
7+
import StreamButton from './StreamButton';
68
import style from './style.module.scss';
79

8-
interface ConfMediaBarProps {
9-
workspaceId?: string;
10-
}
11-
12-
function ConfMediaBar({ workspaceId }: ConfMediaBarProps) {
13-
const socketUrl = `${env.SERVER_PATH}/signaling/${workspaceId}`;
14-
const socket = io(socketUrl);
15-
10+
function ConfMediaBar() {
11+
const { id } = useParams();
12+
const socket = useSocket(`/signaling/${id}`);
1613
const streams = useConfMediaStreams(socket);
1714

15+
const [isMicOn, setIsMicOn] = useState(false);
16+
const [isCamOn, setIsCamOn] = useState(false);
17+
1818
return (
1919
<div className={style['conf-bar']}>
2020
<ul>
2121
{Array.from(streams).map(([id, stream]) => (
2222
<li key={id}>
2323
<ConfMedia key={id} stream={stream} />
24+
<StreamButton
25+
isMicOn={false}
26+
isCamOn={true} // TODO: 임시로 지정
27+
/>
2428
</li>
2529
))}
2630
</ul>
31+
<StreamButton
32+
{...{
33+
isMicOn,
34+
isCamOn,
35+
setIsMicOn,
36+
setIsCamOn,
37+
}}
38+
/>
2739
</div>
2840
);
2941
}

client/src/components/ConfMediaBar/style.module.scss

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,24 @@
1010

1111
ul {
1212
height: 100%;
13-
padding: 0 10px;
13+
padding: 10px;
1414
overflow: hidden;
1515
overflow-y: auto;
1616

17+
li {
18+
position: relative;
19+
& > div {
20+
position: absolute;
21+
right: 5px;
22+
bottom: 10px;
23+
}
24+
}
25+
1726
li:not(:last-child) {
1827
margin-bottom: 10px;
1928
}
2029
}
30+
& > div {
31+
margin-top: 10px;
32+
}
2133
}

client/src/components/Confbar/index.tsx

Lines changed: 0 additions & 5 deletions
This file was deleted.

client/src/components/Editor/index.tsx

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
1-
import { useRef, useEffect } from 'react';
2-
import { useParams } from 'react-router-dom';
3-
import io, { Socket } from 'socket.io-client';
4-
import env from 'src/config';
1+
import { useEffect, useRef } from 'react';
52
import { useCRDT } from 'src/hooks/useCRDT';
63
import { useOffset } from 'src/hooks/useOffset';
4+
import useSocketContext from 'src/hooks/useSocketContext';
75

86
import style from './style.module.scss';
97

108
function Editor() {
11-
const workspace = useParams();
12-
const socket: Socket = io(`${env.SERVER_PATH}/sc-workspace/${workspace.id}`);
9+
const { momSocket: socket } = useSocketContext();
1310

1411
const {
1512
syncCRDT,
Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,29 @@
1+
import { useConfContext } from 'src/hooks/useConfContext';
2+
import useSocketContext from 'src/hooks/useSocketContext';
3+
import color from 'styles/color.module.scss';
4+
15
import style from './style.module.scss';
26

37
function ConfButton() {
4-
return <button className={style['conf-button']}>회의시작</button>;
8+
const { momSocket: socket } = useSocketContext();
9+
10+
const ConfContext = useConfContext();
11+
const { isStart, setIsStart } = ConfContext;
12+
13+
const onClick = () => {
14+
setIsStart(!isStart);
15+
socket.emit(isStart ? 'stop-mom' : 'start-mom');
16+
};
17+
18+
return (
19+
<button
20+
className={style['conf-button']}
21+
onClick={onClick}
22+
style={{ backgroundColor: isStart ? color.red : color.green }}
23+
>
24+
{isStart ? '회의종료' : '회의시작'}
25+
</button>
26+
);
527
}
628

729
export default ConfButton;

0 commit comments

Comments
 (0)