Skip to content

Latest commit

 

History

History
100 lines (71 loc) · 10.2 KB

개발일지.md

File metadata and controls

100 lines (71 loc) · 10.2 KB

개발일지

  • Material Design 적극 채용

    • 중구난방한 폰트사이즈 및 디자인이 규격화 돼있지 않은 문제를 해결
  • Firebase를 이용한 이메일,소셜 로그인 및 비밀번호 재설정 기능 구현

    • 비밀번호 암호화 및 sdk를 통한 소셜 인증 구현을 손쉽게 할 수 있는 장점
  • Styled Component 의 활용

    • 회원가입,로그인,비밀번호 재설정 페이지를 나눠서 중복되는 CSS 코드가 많았는데 Styled Components의 extend 기능을 활용하여 스타일을 컴포넌트화 시킴
  • 메인페이지 디자인

    • Figma Link
    • 구상만 할 때는 구현하고 싶은 기능이 굉장히 많았는데 스켈레톤 디자인을 하면서 데이터 구조, 기능 구현하는데 드는 노력 등등을 생각하니 너무 힘들겠다 싶었다. 일단 그래도 넣어보고싶은 최소한의 기능은 그려넣었지만 과유불급이라는 말이 있듯이 아주 작은 것부터 일단 쌓아올리면서 개발해보자. 완성 후에 시간이 남고 욕심이 든다면 그 때 기능을 추가해도 나쁘지않다. 그리고 나 자신이 쓸 예정이기 때문에 내가 불편하다면 기능을 추가해보겠지..
  • Firebase NoSQL 데이터 추가 작업

    • 어려운 작업은 아니었다. firebase 문서에 따라 데이터베이스 참조 경로만 잘 입력하면 데이터를 넣을 수 있었다.
    • 데이터 구조
      • 데이터를 어떻게 꺼내 쓸지 고려하면서 짜봤는데 잘 짠건지 아닌지도 잘 모르겠다. 나중에 개선사항이 있으면 바꿔야 할 듯 하다.
      • ToDo와 Note의 컬렉션을 따로 구분하지 않고 한 곳에 넣어서 isNote라는 flag로 구분해서 쿼리문으로 꺼내오는게 더 나을듯하다. 데이터베이스 안에서 ToDo와 Note의 다른 점은 isDone 프로퍼티가 필요하냐인데 나중에 Note <-> ToDo 변환 기능을 넣을 때 어차피 넣어야 하니까 Note 여도 isDone은 있어야함.
    • 데이터를 추가할 때 Recoil State와 데이터베이스에 함께 넣어줌.
  • Firebase 데이터 읽기 작업

    • 새로고침 시 처음 렌더링 때 그 날짜의 데이터를 데이터베이스에서 읽어온다.
    • 읽어온 데이터를 Recoil State에 추가한 후 렌더링.
    • 할일을 추가할 때마다 State에도 넣어주고 있으므로 snapshot을 쓰지 않더라도 바로 렌더링 할 수 있었다.
  • Recoil Selector 의 기능

    • 진행중인 할일과 완료된 할일을 같은 State에서 두번의 map에 나눠서 렌더링을 하고 있었는데 Selector로 2차 가공을 한 뒤 최적화를 할 수 있었음.
    • 6/2 추가
      firebase에서 note와 todo를 같은 콜렉션안에 보관하고 있는데 클라이언트 쪽에서는 나눠서 보관을 하고 있었음. db에서 한곳에 보관하고 있기에 쿼리를 나눌 필요도 없어서 데이터를 가져온 뒤 클라이언트쪽에서 todo와 note를 분리하는 쪽으로 리팩토링함. 진작에 왜 이렇게 안했는지 의문..
  • 클릭 이벤트로 state 수정해야하는데 어떤 엘레멘트를 선택했는지 구별하는 효율적인 방법을 못찾겠음. className으로 구별할 수 있지만 모든 자식태그에 같은 className을 다 넣어도 되는건가? 싶어서 다른 방법을 모색중.

    • 해결방법
      • 원래라면 트리거 돼야할 엘레멘트의 모든 자식들한테도 클래스를 넣어야했지만 Element.closest() 메소드를 이용해서 트리거 클래스를 부모한테만 넣어도 될 수 있게 하였다
  • React.memo 의 사용

    • React Developer tool을 사용하여 렌더링을 시각적으로 확인하니 불필요한 렌더링이 많이 확인되었다. 예를들면 절대 변하지 않는 Nav 컴포넌트나 todo를 만드는 Form 등이다. 때문에 state와 props의 변화가 없는 Nav,ContentForm 컴포넌트를 React.memo로 감싸주었다.
    • 또한 map으로 생성하는 li태그인 ToDo 컴포넌트 안의 인풋 밸류가 변할때마다 state의 변화를 주었는데, 그 때 map으로 생성된 다른 ToDo 컴포넌트들이 렌더링되길 원하지 않았기에 ToDo 컴포넌트도 React.memo를 사용하였다.
    • 렌더링최적화를 위한 React.memo를 무작정 도배하지 않고 쓸 때, 안 쓸 때를 구분하여 바람직한 성능 최적화를 기대해보고싶다.
  • 인풋태그의 밸류가 바꼈는데 화면에는 적용안되는 버그

    • 며칠동안 애써봤지만 해결이 안됨..
    • 에디터의 타이틀 <-> 리스트의 타이틀 양방향으로 수정할 수 있고 연동이 되게하려고 했다. recoil의 상태관리든 react-hook-form의 useFormContext든 양방향 수정 및 재 렌더링은 문제가 없었다.
    • 리스트의 제목을 클릭하면 URL의 id파라미터가 바뀌어 에디터의 내용도 바뀌어야하는데 에디터의 제목을 수정하기전이면 잘 작동하지만 수정하고 난 후 리스트를 클릭하면 에디터 내용이 화면에서 안바뀌는 버그가 있었다..
    • 크롬 데브툴로 보면 input 태그의 value는 잘 바뀌는데 화면에는 안그려진다?
    • 버그에 져서 구현하고싶었던 기능을 포기했음
  • 에디터 내용을 클라이언트 & DB에 저장하기

    • 페이지가 로드될 때 id 파라미터에 해당하는 글을 가져와서 tui editor에 적용하는 로직
    • 처음엔 onBlur 이벤트로 state에 저장하는 로직을 짰었는데 에디터에 그냥 글을 쓸 때는 원래 생각한대로 잘 동작했지만 에디터에서 툴박스를 클릭할 때 blur 이벤트가 발생해버림
    • 에디터에 내용을 주입하는 로직과 에디터에 쓴 글을 저장하는 로직의 atom이 같다보니 이런 버그가 일어남.
    • 에디터에서 툴박스 클릭 -> blur 이벤트로 글에 스타일이 적용되기 전에 setter함수 작동 -> deps에 해당 state가 들어가있는 effect가 다시 작동해버려서 결국 스타일이 다시 되돌아가버림
    • 해결한 방법
      • 에디터에 내용을 주입하는 로직은 id 파라미터가 바꼈을 때, 페이지가 처음 로드 됐을 때이므로 flag state를 만들어서 의도대로 작동되게 함
      • 데이터를 저장하는 로직은 blur 에서 떼내어 디바운싱을 이용한 keydown 이벤트로 붙임(글을 다 쓴 후 창을 바로 닫거나 바로 새로고침하여 blur이벤트가 안일어날 최악의 상황을 가정.)
  • 리스트 기능 구현에 있어서

    • 원래는 모든 태스크들을 날짜로 나눠서 DB에 보관하고 있었는데 리스트는 날짜에 상관없이 넣고싶은 태스크를 넣어서 카테고리화 할 수 있는 기능이다.
    • 그래서 따로 리스트를 위한 DB 구조를 또 짜야 했었는데 정말 익숙치 않았고 익숙치 않은만큼 효율적인 데이터구조를 짜는게 너무 어려웠다.
    • Firestore NoSQL DB의 유연성에 힘입어 기능구현에 성공하긴 했다. UID - 'Lists' 문서 안에 생성된 리스트의 정보를 배열로 넣었고 각각 리스트에 들어가는 태스크는 리스트 개수만큼 하위 컬렉션을 생성해 그 곳에 추가하는 방식으로 어떤 리스트에 어떤 태스크가 들어가있는지 알 수 있는 구조를 만들었다.
    • 기능 작동에 문제가 없으면 결국 맞는 구조라고 생각하지만 단언코 효율적이진 않은것같다. 나중에 데이터베이스 구조화에 견식이 넓어진 후에 다시보면 과연 어떨까 싶다.
  • react-router의 리렌더링 문제에 관하여

    • react-router가 제공하는 메소드(useNavigate, useParams 등)를 쓰는 컴포넌트는 URL이 바뀔 때마다 리렌더링이 된다.
    • 그로 인해 dail의 최상위 컴포넌트인 Main 컴포넌트가 원치않는 리렌더링이 일어났다.
    • Main 컴포넌트에서 쓰이던 useNavigate, useParams는 어떤 컴포넌트에서 쓰여도 문제없는 로직이라 최상위 컴포넌트에 놓았던 것이여서 GlobalLogic 이라는 아무것도 반환하지 않는 컴포넌트를 만들어 그곳에 배치하였다.
    • 따라서 URL이 바뀌어 router가 렌더링되어도 Main 컴포넌트를 렌더링되지 않게 할 수 있었다. 과연 이게 베스트인지는 잘 모르겠다.
  • 리팩토링

    • 혼자하는 프로젝트였다보니 거의 주석을 달지 않았는데 그 때문인가 어떤 코드가 중복되어있는지, 불필요한지 알기가 참 어려웠다.
    • 따라서 컴포넌트안의 비즈니스 로직과 jsx가 어떠한 내용인지 주석을 달고 무분별하게 어지럽혀있는 import 구문들도 그룹핑하여 정리하는게 좋겠다고 생각했다
    • import 구문은 dependencies components states types sources styles
  • 모두보기 페이지에서 할일 개수가 많아지면(200개이상) 렌더링 때마다 지연시간이 너무 긺. 개선해야될 듯

    • 이거는 확실히 경험해봐야 할 이슈인 것 같다. 느려지는 이유와 해결법을 확실하게 캐치하고 기억해야할 듯
    • 일단 지금 떠오르는 건 렌더링 횟수 자체를 최적화 하는 것. URL parameter가 바뀔 때마다 ListConstructor 컴포넌트가 렌더링이 되는데 memoizing을 하면 되지 않을까
    • recoil 상태관리로직에서 선택된문서를 찾는 로직이 배열에서 find 메소드를 쓰고있는데 데이터 저장로직을 key,value형식의 Object, Map 으로 리빌딩하면 렌더링이 자주 일어난다해도 데이터를 찾는 시간복잡도가 O(n) 에서 O(1) 이 되니까 고쳐지지않을까
    • 둘 다 따로따로 해보고 효과있는 걸 적용하자. 두개 다 좋으면 둘 다 적용
    • 상태관리 로직은 이미 object로 된 allDocs state가 있었기 때문에 한 줄만 바꾸면 됐다. 오히려 왜 지금까지 object가 아니라 array 에서 find를 쓰고있던거지 하는 생각이 들었다. 결과는 크롬 데브 툴 퍼포먼스 측정으로 330ms에서 310ms로 별 다른 차이는 없었지만 배열 크기가 작아서 그런거고 할 일의 개수가 4자리정도 되면 확연히 차이 날 것이다.