> [!date] published: 2023-02-03 리액트로 간단히 페이지나 끄적이던 내가... 갑자기 로그인 + Socket.io를 이용한 실시간 채팅/게임 서비스를 만들어야 한다고? ![[b2bdb049-a83c-470f-beb8-0da1dd5a90ec.png]] 3주만에 리액트 마스터 가보자고 👊 기능 구현이 급한 상황이라 정말 이리저리 급하게 땜빵만 하고 있지만 (어째서.. 프론트를 나 혼자 하게 되었는가...) 그래도 이 과정에서도 급하게 머릿속에 들어가지고 있는 내용들이 많지 않을까 싶어서... 이런저런 생각한 내용들이나,, 땜질한 내용들 최초공개 합니다. (쟤는 왜 저렇게 처리했다냐... 하는 것들이 100%일 것이라 미리 부끄럽습니다..) ## 🌟 소켓 관리하기 사용자가 홈에 들어오는 시점부터 소켓을 연결해서, 사용자가 창을 닫기 전까지 오직 하나의 소켓을 가지고 있고, 하위 컴포넌트들에서 계속 이용해야 했다. 처음에는 전역으로 선언한 뒤에 import해 오는 방식으로 했었는데, 뭔가 이렇게 하면 안될 것 같아서 (이유는 없음. 그냥 뉴비의 감...>?) 상태로 관리하기로 했다. 전역 상태관리 툴을 recoil로 사용하고 있는데, 찾아보니 recoil로 소켓을 관리했던 팀들에서 상태 업데이트 문제가 발생했다고 해서 소켓만 context api를 이용해서 관리하고 있다. (관리라곤 하지만 사실상 그냥 이벤트 on, off, emit만 하고 있음) 근데 이제 와서 생각해보니 왜 굳이 socket이 상태가 되어야 할까? 싶어서 좀 더 고민해봐야 할 것 같다. ## 🌟 전역/지역 모달 DM목록 확인, 유저 프로필 확인 (본인이든, 친구든), 친구 목록 확인을 기본으로 해서 이곳저곳에서 모달을 많이 쓰고 있기 때문에 처음 설계할때부터 모달을 전역으로 빼 두고, recoil로 상태를 관리하는 방법을 적용하고 있었다. 그런데 전역으로 관리하는 편이 구조적으로는 훨씬 깔끔하긴 한데, 모달 온오프를 제외하고도 모달 오픈시에 호출한 컴포넌트가 보내줘야 하는 props가 필요한 모달들이 꽤 생겨서 상태의 크기가 불필요하게 커지는 문제가 생겼다. (문제가.. 맞겠지요?) 게다가 모달이 중첩되는 상황도 많아졌는데 그걸 모두 전역으로 옮기니... 구조가 이상해지기도 했다. 그래서 모든 모달을 전역 모달로 만들기보다는 위에서 나열한 큼직큼직한 기능 모달들을 제외하고는 지역 모달로 바꿔주기로 했다. (아직 해보질 않음) ## 🌟 setState는 비동기였다. 실시간 핑퐁게임의 특성상 랜더링 횟수가 굉장히 많다. 따라서 상태 변화도 굉장히 많다. 처음에는 당연히 setState가 동기적으로 작동할 것이라고 생각해서 게임에 필요한 정보들 (플레이어의 위치, 공의 위치, 점수 등등)을 모두 별개의 state로 정의했었는데, setState가 비동기적으로 작동했기 때문에 뭔가 이전의 state를 가리키기도 하고, 어쨌든 내가 의도한 방식으로 재랜더링이 일어나지 않았다. setState가 비동기적으로 동작한다는 것이 게임 랜더링 구조를 바꾼 유일한 이유는 아니지만, 아무튼 setState가 비동기적으로 동작한다는 것이 좀 충격이었다. ## 🌟 게임 랜더링 구조 삽질 처음에는 Client에서 뭔가 조작을 하고, 그 조작이 발생하면 그 조작으로 인해 바뀐 정보를 Server로 보내고, Server에서는 단순히 그 정보를 다른 Client에게로 전달만 해 주는 방식을 생각하고 있었는데, setState가 비동기적으로 동작하는 바람에 업데이트 전 state를 계속 참조하는 문제도 발생했었고, 두 Client에서 완전히 동일한 방식으로 업데이트가 되는 게 아니기 때문에 동기화 부분에서도 문제가 발생했었다.. 결국에는 플레이어 움직임을 제외한 모든 게임 동작 (공을 매 일정 시간마다 움직여주기 / 스코어 판단하기 등) 을 Server에게로 넘겼고, 플레이어 움직임이 바뀔 때마다 Server에 그 정보를 알리는 방식, 그리고 Server가 보내주는 정보를 그대로 랜더링하는 구조로 바꾸었다. ## 🌟 Link 와 useNavigate react-router-dom의 Link, useNaviagate이다. 옛날에 처음 이게 뭐지? 하고 검색해 봤을 때 언뜻 Link 사용을 지양하라는 글을 본 적이 있었던 것 같아서 (사유는 정확히 기억안남ㅜ) 조금 번거롭더라도 useNavigate를 사용했었는데, 이번에 다시 찾아보니 웬걸 그냥 컴포넌트 타입 / 함수 타입 의 차이었다 (;;) 그래서 Link 컴포넌트는 그냥 아묻따 페이지를 이동시켜줘야 할때 사용하고 있고, useNavigate는 페이지 이동 전에 뭔가 작업을 해 줘야 할 때 (게임 매치 이벤트를 보낸다던가,, 등등) 사용하고 있다. ## 🌟 useEffect와 state 초보적인 실수 주의. useEffect 내부에서 아무 생각 없이 상태를 바꾸어 주지 말자. (이상 무한 재랜더링으로 브라우저를 먹통으로 만들어버렸던 사람의 말이었습니다.) ## 🌟 얕은 비교 자세한 내용을 깊게 공부하고 정리할 시간은 전혀 없어서 일단 참고한 링크로 내용을 대체합니다... [React Virtual DOM 비교 원리와 얕은 비교](https://babycoder05.tistory.com/entry/React-Virtual-DOM-%EA%B3%BC-%EB%B9%84%EA%B5%90-%EC%9B%90%EB%A6%AC%EC%99%80-%EC%96%95%EC%9D%80-%EB%B9%84%EA%B5%90?category=1023016) 상태를 객체로 관리하는 일이 많았는데 왜인지 업데이트가 안되어서 한참을 해맸었는데... 이런 이유였다. 그래서 완전히 새로운 객체를 만들어서, 그 안에 값을 복사해서 넣어주고 업데이트 된 값만 따로 다시 넣어주는 방식으로 "상태가 바뀌는 것"을 인식시켰다. 문제는 내용물이 같은 새로운 객체를 넣어줬을 때에도 그 주소가 다르기 때문에 상태 업데이트로 인식되는 것이었는데... 적으면서 생각해보니 이런 경우는 애초에 상태를 업데이트 해 주지 않으면 되었을 것 같다! ## 🌟 계속된다... 😇 아직 할일이 수두룩빽빽이라 아직 마주치지 못한 문제가 많을 것이라 너무 무섭지만.. 흑흑 이 과제 돌입한지 이제 딱 3주 되어가는데 3주 전의 나와는 확실히 다른 사람이 된 것 같다는 생각이 든다.. (실력이 늘었다는 의미로 한 말이긴 한데 사실 조금 흑화한것같음 세상이 비뚤게 보인다.) 암튼 힘내보자고 얼마 안남았다 👊💥👊💥👊💥👊💥