Kim-aide / frontend

https://kim-aide.github.io/frontend/
0 stars 0 forks source link

[FEAT] 단일 회의 참여 화면 신규 생성 #14

Closed wzrabbit closed 2 months ago

wzrabbit commented 2 months ago

이슈 번호

close #3

작업 요약

본 PR에서는 참가자 한 명에 해당하는 회의 화면을 나타내는 컴포넌트를 신규 생성 및 구현했습니다. -- <UserVideo>

1️⃣ <UserVideo> 신규 생성 및 구현

2️⃣ 라이브러리 설치

참고/인용 자료

1️⃣ 작동 화면

실제 streamManager 객체가 들어가서 작동하는 것은 아닙니다. 일부 프로퍼티만을 사용한 가짜 객체를 이용해 storybook에서 테스트한 것입니다. 해당 스토리에서는 여러 작업이 규칙성 없이 자동으로 실행되는 모습입니다.

https://github.com/user-attachments/assets/b061e107-bc82-471e-b9f0-5252586e1514

2️⃣ 참고 자료

제 OpenVidu 연습용 저장소인 webrtc-frontend-practice에서 앞서 본 기능을 실제로 테스트하기 위한 커밋입니다.

OpenVidu의 공식 문서/치트시트의 정보입니다.

3️⃣ 원리 설명

UI 자체는 어렵지 않으나 라이브러리와 연관되어 있는 로직이다 보니까 라이브러리를 이해하고 이를 바탕으로 어떻게 구조를 잡아야 하는지가 훨씬 오래 걸렸던 컴포넌트입니다...! 어떻게 이 컴포넌트가 OpenVidu 라이브러리와 맞물려 작동하는 것일까요?

플로우는 아래와 같습니다. 당연하지만, 이 방법은 유일한 방법이 아니며, 수많은 방법들 중 하나라고 생각합니다.

image

  1. 부모(Application)로부터 streamManager 객체를 prop으로써 부여받습니다.
  2. <UserVideo>는 제공받은 streamManager를 바탕으로 비디오를 송출합니다. 또한, useStreamManagerProperties 커스텀 훅으로부터 정보를 얻기 위해 streamManager 객체를 전달합니다.
  3. useStreamManagerProperties<UserVideo>로부터 필요한 객체인 streamManager를 받으며, 이 streamManager에 대한 리스너를 등록합니다. 다양한 리스너들을 등록할 수 있지만, 현재 이 컴포넌트에서 제공해야 하는 기능을 생각했을 때 아래의 세 가지 리스너를 등록해야 한다고 판단했습니다. 이 리스너들이 호출되면, 이 커스텀 훅이 지니는 state가 업데이트됩니다.
    • streamPropertyChanged: 프로퍼티가 변경된 경우 호출되는데, 이 안에는 videoActive라는 프로퍼티가 있기 때문에 참가자가 캠을 켜거나 끈 경우 reason 값을 통해 videoActive가 변경되었음을 알 수 있으며, setVideoActive(true | false)를 통해 최종적으로 캠의 켜기/끄기를 반영할 수 있습니다.
    • publisherStartSpeaking: 참가자가 발언하기 시작해 음성이 감지되면 호출됩니다. 이 이벤트가 호출되었을 경우 state를 업데이트해 주면 됩니다.
    • publisherStopSpeaking: 참가자가 발언을 끝내 음성이 더 이상 감지되지 않으면 호출됩니다. 이 이벤트가 호출되었을 경우 역시 적절하게 state를 업데이트해 주면 됩니다.
  4. useStreamManagerProperties 커스텀 훅에서 리스너가 실행되어 state가 업데이트되면, <UserVideo>에도 영향을 주게 됩니다.
  5. <UserVideo>는 변경된 state를 기반으로 자신의 UI를 상황에 맞게 업데이트합니다.

4️⃣ 질문/답변

❓ 왜 모든 streamManager들을 통제할 수 있는 최상단의 <App> (또는 그에 준하는 커스텀 훅)에 리스너를 두지 않는 것인가요?

💡 최상단의 로직이 복잡해지고 관리가 어려워질 것이라고 판단하여 그렇게 하지 않았습니다.

그래서, 각 UserVideo에 커스텀 훅을 두어, 각 streamManager를 리스닝하도록 구현해, 최신화된 값을 얻는 한편 재사용성을 늘리고, 로직을 간단하게 분리시킬 수 있는 장점을 얻어내고자 이러한 선택을 했습니다.

❓ 리스너, state 사용하지 않아도 일단 이벤트가 실행되면 streamManager 객체의 값은 자동으로 변경되는데, 왜 굳이 리스너와 state를 사용해야 하죠?

💡 최신화된 정보를 성공적으로 얻기 위함입니다.

그렇기 때문에, 리스너를 사용해 그 이벤트가 실행되는 타이밍을 입수하고, 이를 바탕으로 React가 인식할 수 있는 형태인, 바로 state를 업데이트 하는 방법을 사용하는 것입니다.

논의

논의보다는 이후 해야 할 고민을 적어둡니다.