개발새발 로그

[2023-10-26] TIL - 노션 클로닝 프로젝트 회고 본문

카테고리 없음

[2023-10-26] TIL - 노션 클로닝 프로젝트 회고

이즈흐 2023. 10. 26. 22:21

 

노션 클로닝 프로젝트가 끝났다.

노션클로닝을 진행하면서 자주 쓰일 것 같은 기능들을 많이 배웠다.

이 프로젝트를 더 기억하고,

진행하면서 부족했던 점을 생각하면서 기록하려고 한다.

 

미래의 내가 보고싶을 때 올 수 있도록!

 

📝개발하고 학습한 기능

1. history API를 이용한 라우팅
2. fetch를 이용한 API 요청
3. API요청으로 받아온 데이터를 임의대로 정제하는 방법(ToggleData를 추가함)
4. 데이터가 트리형태로 되어있다면 재귀함수를 이용해 모든 데이터를 온전히 출력하는 방법
5. 이벤트 위임(하나의 div에 다수의 이벤트를 관리하는 방법)
6. 커스텀 이벤트
7. 경로를 이동했을 때, 경로를 재클릭했을 때의 예외처리를 해야한다는 점(컴포넌트에서는 id정보를 받고 어떤 상황인지 검사해야함)
8. contenteditable을 이용한 Rich한 에디터 만드는 방법
9. contenteditable에 innerHTML로 데이터를 넣고 재 렌더링하면 커서가 계속해서 맨 처음으로 가는 문제 해결
10. 디바운스 기법
11. execCommand() 기능
13. 마우스 이벤트(up,down,click)으로 마우스가 드래깅 중, 드래깅 종료 상태를 확인하는 방법(드래그시 서식바 출현기능)
14. 버튼 클릭시 요소가 움직이는 애니메이션 기능(transform, transition)

 

내가 개발하면서 배운 기능을 응용하거나 새로 배운 것들을 생각하고 정리해봤다.

나열해보니 생각보다 별로 없었다..

사실 CSS 스타일링에 시간을 제일 많이 썼다.

CSS스타일링이 간단하면서도 어려웠다.

 

나는 이쁘게 하고 싶은데 아직 디자인 감각이 없는 것 같다..

디자인 감각을 키우기 위해 좀 더 CSS쪽을 공부해야될 것같다.

 

구성도

 

 

기능 설명

 

💢발생한 에러

1. 문서리스트에 문서마다 토글 기능을 넣어 누르면 하위 문서들을 출력해주는 기능을 구현하다가 만난 문제점(해결 못함)

 

문서 리스트를 누르면 해당 문서의 하위문서(1 depth만)를 출력하는 기능이었는데

여기서 내가 처음에 이 기능을 아래와 같이 개발했다.

1. 토글을 누르면 해당 문서의 아이디가 이전에 토글되었었는지 확인하고, 상태에 배열로 누적 저장
2. 토글이 되었었다면 해당 문서의 아이디에 해당하는 데이터를 상태에서 지워줌
3. 그리고 history.pushState로 해당 id에 해당하는 문서로 이동 - 이때 다시 문서 리스트를 렌더링 해줌
4. 토글정보가 저장된 데이터로 재 렌더링된 문서 데이터를 보여줌(즉 toggle이 true면 재귀함수를 실행해 펼쳐서 보여줌)

여기서 토글을 했을 때 문제는 재 렌더링이 된다는 점이었다.

재 렌더링을 하게되면 CSS 애니메이션을 쓸 수 가 없었다..😂

 

이걸 생각하지 못해서 해결하려 했지만 시간이 부족했다.

만약 재 렌더링을 하지않고 진행한다면 어떤 방법으로 해야할까?

 

모든 문서를 펼친 상태로 저장하고,

css로 펼쳐있는 문서들을 숨겨서 진행해야할까?

 

아니면 CSS말고 다른 방법이 있을까?

 

다음에는 이런 문제도 생각하고 개발을 계획해야겠다고 생각했다.

 

2. 하위 문서들이 토글되어 펼쳐진 상태에서 상위문서를 토글로 다시 접으면 모든 문서가 안보이게 되지만 하위문서들의 토글상태가 저장되어있어 다시 펼치면 그대로 유지되는 문제점

 

이건 문제점이라기 보다는 디테일한 부분이었다.

펼쳐진 것을 저장되게 하는 것을 좋다고 할 수 있고, 아닐 수도 있기 때문에

 

하지만 이런 toggle상태가 저장되어 있으면 토글하는 재미가 없을 수 있기 때문에 없애야했다.

 

해결 방안

toggle 정보를 저장할 때 해당 문서의 루트 문서의 id를 같이 저장하는 것이었다.

그래서 만약 루트 문서가 토글되어 toggle정보가 사라지면 그 루트 문서의 id를 갖고있던 하위 문서들도 모두 없애주는 것이다.

즉 데이터를 아래와 같이 저장하는 것이다.

3. editor 부분에 title과 content 데이터를 보여줄 때 같은 문서를 재클릭하거나 , 뒤로 가기 버튼을 누른 후 앞으로 가기 버튼으로 다시 되돌아 왔을 때 문제점

 

데이터를 뿌려줄 때

만약 문서를 재클릭하거나 뒤로갔다가 앞으로 오면

데이터가 없어지는 현상이 생겼다.

이는 아래와 같은 문제때문에 생긴 현상이다.

 

뒤로 가기 또는 앞으로 가기 버튼을 누르면 App.js route()를 호출한다.
그러면 보내주는 nextState.id와 state.id가 같은 경우가 생기게 된다.(똑같은 문서를 재 클릭하는 경우도 있음)
같으면 API 요청을 보내지 않는 조건이 있어
이때 this.state를 nextState.id로 덮어버리면 this.state에 있던 기존 값이 초기화 된다.
즉 this.state가 id를 제외하고 빈 값이 되어버린다.
그러므로 id가 같을 경우에는 기존 값을 사용해야 한다.

 

그래서 나는 데이터를 보내줄 때 1가지 조건 + 2가지 조건을 넣었다.

 

1. documentEditComponent의 state.id 값이 받아온 id값과 다를 경우
2. documentEditComponent의 state.id 값이 받아온 id값이 같고, State.document값이 존재하며, State.documentList값이 존재할 경우
3.documentEditComponent의 state.document값이 존재하지 않거나 State.documentList값이 존재하지 않을 경우

 

이렇게 나눈 이유는 위에서 설명했듯이

만약 id가 바뀌면 제대로 데이터를 다시 출력한다.

 

하지만  this.state =nextState가 기본으로 되어있으면  받아온 id와 현재 저장된 id가 같아질 때는 데이터가 다시 초기화하게 된다.

그래서 위와 같은 조건을 통해 

현재 id와 받아온 id가 같을 경우에는 api요청을 하지 않고, this.state도 그대로 둔 상태에서 데이터를 뿌려주는 것이다.

 

 

4. 트리로 된 데이터를 재귀함수로 풀어냈을 때 기능 저하?

 

트리로 된 데이터를 재귀함수로 찾다보니 혹시 모를 기능 저하가 있진 않을까? 생각했다.

하지만 아직까지는 문제가 발생하지 않았다.

 

 

5. editor의 title을 수정하면 문서 List에 있는 문서의 제목도 같이 바뀌는 기능을 구현할 때 문제점

 

노션은 에디터의 제목을 수정하면 문서리스트에 있는 제목도 함께 실시간으로 바뀐다.

 

나는 이 기능을 그냥 타이핑할 때마다 API요청하는 것에

문서 리스트도 재 렌더링하게끔 콜백 함수를 던져줬다.

즉 재 렌더링만 하게끔 했다.

 

근데 문제는 현재 디바운스 기법으로 임의로 설정한 시간에 타이핑이 멈추면 API요청을 보낸다.

 

그러면 2초뒤에 문서 리스트의 제목이 바뀌는 것이다.

실시간으로 되지 않아 0초로 바꿨더니 가능은 했지만 그렇게 되면 API요청이 너무 많아졌다.

 

해결하지 못했지만

이전에 말씀해주신 낙관적 업데이트 방법을 쓰면 되지 않을까? 생각했다.

API요청을 줄어들게 되겠지만

그래도 렌더링은 타이핑할 때마다 진행되어야 했다.

 

다음에는 꼭 낙관적 업데이트 방법을 생각하고 구현을 해야겠다..

 

6. 에디터 서식을 execCommand() 기능을 사용해서 생긴 문제점

 

문제는 deprecated된 기능인 것이다.

아무래도 deprecated된 기능은 되도록 안쓰는게 좋다고 생각했다.

 

하지만 편리해서 일단 적용해서 사용했다.

 

다른 방법은 없을까? 해서 찾아봤는데

Clip board API라는 것을 대신해서 사용한다고 해서 보았더니

약간 복사의 개념이었다.

 

해당 텍스트를 가져오고 복사하고 읽어오고 할 수 있는 기능이었는데

그러면 읽어와서 서식해주고 다시 보내주면 되지 않을까 했지만 시간상 생략했다..

 

이런 기본적인 서식은 어떻게하는지 다시 찾아봐야할 것 같다.

 

7. contenteditable에 innerHTML로 데이터를 넣고 재 렌더링하면 커서가 계속해서 맨 처음으로 가는 문제

Contenteditable의 문제

만약 타이핑을 할 때마다 this.setState()로 현재 editor 상태에 저장하고 

Contenteditable에 바로 렌더링을 하려고 한다면(querySelector로 값을 넣으려고 한다면)

커서가 계속 처음으로 가게 되는 현상이 생긴다.

이는 textarea에서도 계속 렌더를 하게 되면 커서가 끊기는 현상이 생긴다.

 

그러므로 아래와 같이 해결을 해야 한다.

1.타이핑 시 this.setState()로 적은 내용을 계속해서 저장한다.

2.이 때 setState()에서는 두가지 조건을 수행한다.

 - 현재 저장된 id와 받아온 nextState.id가 다른 경우 : 다른 문서로 이동한 경우에는 예외로 처리해줘야 한다.

 - Isinitialized==true인 경우 : 상위로 부터 받아온 데이터의 contenttitile을 수행 안 한 초기 상태이므로 render()함수를 수행하고 , isinitializedfalse로 만들어준다(단 한번만 렌더링하기 위해서)

 - 위 두조건과 상관없이 this.statenextState를 항상 저장한다.

 

이렇게 하면 render()에서는 단 한번의 데이터를 정제하는 활동을 한다.

1.split으로 content를 각각 나눠 “#”을 포함한 데이터가 있는지 확인하고 있다면 h1,h2,h3 태그로 바꿔준다.

2.만약 현재 생성된 모든 문서 중에 포함된 content가 있다면 해당 content를 링크버튼으로 만들어준다.

정제한 contentquerySelector.innerHTML로 넣어준다.

 

해결은 했지만 

내용을 작성하고 새로고침, 즉 렌더링이 되어야만 #과 같은 서식이나 링크 기능이 적용되었다.

 

이는 다른 방법으로 

내용을 작성하다가 스페이스바 혹은 엔터를 눌렀을 때 렌더를 요청하고,

마우스 커서가 처음으로 가는 현상은 getSelection()과 같은 기능으로 커서를 마지막으로 고정 시키면 되지 않을까?

생각했다.

 

하지만 이 역시 시간문제로 구현하지는 못했다..

사실 될지 안될지 가능성을 생각하지 못했다.

 

왜냐하면 만약 중간의 내용에 커서를 두고 스페이스 바나 엔터를 누르면 무조건 커서가 마지막으로 가지 않겠는가?

이러한 예외상황도 처리해줘야 했는데

예외상황이 이것 말고도 더 있을거라 생각이되었고, 일단 간단하게 구현만했다.

 

사실 에디터에서 가장 중요한 부분인데

후회가 많이 된다.

 

소감

솔직히 아쉬운 점이 많았다.

CSS 스타일링도 아쉬웠지만

 

기능 자체가 디테일하지 못했다.

 

만약 디테일하게 하려면 모든 기능을 다시 짜야하는 상황이 예상됐고,

그럴 엄두를 내지 못했던 적도 있었다.

 

내가 짠 코드가 아깝다는 생각이 들었더 것이다.

이런 상황이 진짜 엄청 많이 생길텐데

아직 익숙치가 않다.

 

이런 상황이 생기지않으려면 기능 명세를 정확히 하고,

계획을 잘 해야겠다고 생각했다.

 

처음부터 단추를 잘 꿰매야 했다.

기능을 개발하면서 생각해버려서 이런 문제가 생긴 것 같았다.

 

만약 이 기능을 이렇게 하면 다른 기능에 영향이 있지 않을까?

하는 생각을 꼭 해야겠다고 다짐했다.

 

그리고 CSS스타일링을 빠르게 할 수 있도록 처음부터 div를 잘 나눠야겠다고 생각했다.

div에 저장된 클래스 네임이나 dataset 속성이 바뀌면 안되니까 

이런 부분에 신경을 쓰다가 시간을 소모했다.

 

아직 많이 부족하다

 

하지만 나는 이 프로젝트 자체를 정말 외부의 도움을 최소화해서 오로지 내 생각으로만 만들었다는 것에 뿌듯함을 느꼈다

과거에는 무조건 검색해서 모든 기능 살펴보거나 예시를 찾아봤는데

지금은 그래도 유추하고, 해결방안을 자기주도적으로 찾아갔다.

 

조금만 더 힘내야겠다.

728x90
반응형
LIST