제작 중인 랜덤매칭 언어교환 플랫폼은 시간이 다되면 메인 페이지로 이동하여 다시 매칭이 이루어져야 한다. 두 유저가 매칭을 통하여, useState()를 통해 5분이라는 시간을 가지게 된 후, state
값이 0분 0초를 가리키게 되는 경우 페이지로 이동시키도록 했다.
useState()
를 통해 시간을 설정하니, 유저가 서로 시간이 다르게 되는 경우가 발생했다. 접근 환경에 따라, 미팅 페이지 진입 시간이 다르고, 진입 시에 생성되는 state
선언이 달라지기 때문에, 테스트 결과 5초 정도까지 차이가 나타나게 되었다.
useState()
외에 시간을 공유할 수 있는 로직을 고민해본 결과, 소켓 이벤트를 활용하여 미팅페이지 진입부터 유저끼리 시간을 공유한다면, 똑같이 맞출 수 있다는 생각을 하게 되었다.
신규 로직 : 타이머 로직
1. 룸생성자를 기준으로 타이머를 만든 후, 룸 입장자에게 시간 데이터를 1초마다 보낸다. 이후 각자의 시간 데이터를 자신의 로컬에 렌더링한다.
2. 타이머 카운트 처리 역시 룸 생성자가 조작한다. 룸 입장자에게는 매초마다 단순 결과값만 보낸다.
const [minutes, setMinutes] = useState(5)
const [seconds, setSeconds] = useState(0)
...
...
useEffect(() => {
// timer 로직 요약 설명
// 생성자 -> 입장자 이루어지는 단방향 로직 설정
// timer는 방 생성자가 연산하고 관리한다.
// 방 생성자는 1초마다 연산한 timer를 제공
// 방 입장자는 1초마다 제공되는 timer를 렌더링만 해야한다.
// 방 생성자용 timer 설정
const countdown = setInterval(async () => {
if (room.isCreatedRoom) {
const data = {
minutes: minutes,
seconds: seconds,
}
openvidu_timer_minites.current.textContent = minutes
openvidu_timer_seconds.current.textContent =
seconds < 10 ? `0${seconds}` : seconds
openvidu.publisher.session.signal({
data: JSON.stringify(data),
type: 'timerShare',
})
if (seconds >= 0) {
setSeconds(seconds - 1)
}
if (seconds === 0) {
if (minutes === 0) {
if (heart) {
const heartData = {
cnt: 1,
fromUser: user.id,
name: 'like',
route: 'like',
toUser: peerUser.id,
}
await dispatch(heartEvent({ accessToken: auth.token, heartData }))
}
clearInterval(countdown)
dispatch(ovActions.leaveSession())
window.location.replace('/meeting?rematching=true')
} else {
setMinutes(parseInt(minutes) - 1)
setSeconds(59)
}
}
} else {
// 방 입장자용 timer 렌더 설정
openvidu.session.on('signal:timerShare', event => {
const data = JSON.parse(event.data)
openvidu_timer_minites.current.textContent = data.minutes
openvidu_timer_seconds.current.textContent =
data.seconds < 10 ? `0${data.seconds}` : data.seconds
setMinutes(data.minutes)
setSeconds(data.seconds)
})
if (minutes === 0 && seconds === 0) {
if (heart) {
const heartData = {
cnt: 1,
fromUser: user.id,
name: 'like',
route: 'like',
toUser: peerUser.id,
}
dispatch(heartEvent({ accessToken: auth.token, heartData }))
}
clearInterval(countdown)
dispatch(ovActions.leaveSession())
window.location.replace('/meeting?rematching=true')
}
}
}, 1000)
return () => clearInterval(countdown)
}, [minutes, seconds, heart])