display-none
상태다.document-item
이 문서고, document-list
는 문서 묶음이다(래핑). 따라서 document-item
의 하위문서가 document-list
안에 담겨있다.document-item
과 document-list
는 재귀적으로 구현했기에 형제노드다.nextSibling
을 사용하면된다.여기까지는 맞았다.
그래서 화살표버튼을 클릭할 시 nextSibling
에 display-none
이 토글되게 함.
여기까지는 잘 됐다.
그런데, localStorage
에 isFolded
값을 두고 렌더링시 토글상태를 유지하려했음.
그러나 초기렌더링단계에서 nextSibling
이 선택되지 않는 현상 발생.
한번 알아볼까?
내 구조는 Nav
> DocumentList
> DocumentItem
> DocumentList
(재귀)
이 구조다.
Nav
에서 문서들을 가져와 list
의 상태로 넣어준다. 이때 list
의 setState
를 사용하여 한번 리-렌더 시켜줌.
list
에서 setState
가 발생하면 당연히 item
에서도 setState
를 발생시켜 리-렌더시켜줌.
아하! 일단 가드용 초기값이 있고, setState
로 값이 들어와야 상태가 존재하는구나
여기까지는 이해 완료.
하지만 nextSibling
을 사용하는 item
의 자식컴포넌트에서는 잘 작동한다....
크롬 디버거로 찍어보니, 재귀적 렌더링때문에 아직 요소들이 DOM에 붙지 않아 선택할 수 없었다.
따라서 render()
메소드 맨 마지막에 nextSibling을 선택하는 로직을 넣었더니 잘 작동하는 듯 싶다가도...마지막 문서에만 적용된다. 흠...
구조를 조금 더 바꿧다.
DocumentList
는 그냥 DocumentList
들을 렌더링하기위한 일종의 래퍼.
DocumentItem
은 문서 그 자체. 또한 내부에서 DocumentItem
들을 재귀적으로 렌더링한다.
따라서 item
내부에서 item
관련 로직을 처리할수 있게되었다!
item
조작을 item
내부에서 할수있음!!!
e.target
에 대한 메소드가 많이 필요할 것 같다.
e.target.clientX
: 타겟 왼쪽을 기준으로 0부터 시작하는 X좌표e.target.offsetWidth
: 타겟의 너비cursor: col-resize
:커서 열 리사이즈 가능하게(가로로)이 세 메소드로 구현하였다!
document.addEventListener("mousedown", (e) => {
//마우스 다운시점의 시작 x좌표와, nav바의 너비를 저장해둠.
const startX = e.clientX;
const initialWidth = $nav.offsetWidth;
//마우스가 10px전후로 넘어가면 별로다
if (Math.abs(startX - initialWidth) > 10) return;
const onMouseMove = (e) => {
const newX = e.clientX;
const delta = newX - startX;
const calculatedWidth = Math.max(minNavWidth, initialWidth + delta); // 최소 너비를 250px로 설정
//최대너비는 500px
if (calculatedWidth >= maxNavWidth) {
$nav.style.width = `${calculatedWidth}px`;
//크기를 더 키우려하면(클릭 시점보다 움직인 좌표가 양수면)
if (startX < newX) {
onMouseUp();
}
} else {
$nav.style.width = `${calculatedWidth}px`;
}
};
const onMouseUp = () => {
document.removeEventListener("mousemove", onMouseMove);
document.removeEventListener("mouseup", onMouseUp);
};
document.addEventListener("mousemove", onMouseMove);
document.addEventListener("mouseup", onMouseUp);
});
document.addEventListener("mousemove", (e) => {
const startX = e.clientX;
const initialWidth = $nav.offsetWidth;
if (Math.abs(startX - initialWidth) > 10) {
e.target.classList.remove("resize-cursor");
$nav.classList.remove("thick-border");
} else {
e.target.classList.add("resize-cursor");
$nav.classList.add("thick-border");
}
});
뭔가 살짝 맘에 안드는데...마우스 무브 이벤트를 2번이나 거는게 기분나쁘다.
옵저버패턴을 이용한 구독-알림시스템을 만들거다.
일단 구독하면 상태 변경시 알림이 와야한다
내게 필요한건 문서를 생성하거나 수정하면 getDocuments, getDocument를 다시 호출해야함
따라서 문서를 수정하는 일이 생긴다면, 알림을 이용하여 위 메소드를 호출해보자
이를 토대로 살짝 만들어보면
class Observer {
constructor() {
this.subscribers = [];
}
subscribe(observerCallback) {
this.subscribers.push(observerCallback);
}
unsubscribe(observerCallback) {
this.subscribers = this.subscribers.filter(
(subscriber) => subscriber !== observerCallback
);
}
notify() {
this.subscribers.forEach((subscriber) => subscriber());
}
}
export default Object.freeze(new Observer());
요래된다.
인스턴스를 생성하고 바로 내보내줘서 싱글톤(인스턴스가 무조건 하나만)으로 사용하게끔 할것이다.
계속 새로운 인스턴스가 생성되면 안되잖아?
이걸 이용하여 DocumentPage에서 글이 수정되면, 일단 문서리스트를 가져오는 NavPage에서 다시 문서리스트를 가져오게끔 할것이다.
디자인 패턴이라고 막 엄청 어려운건 아니었다.
결국 방법론이고 작은것 부터 만들어보면 쉽게 이해할 수 있었다.
또한 문제와 마추지지 않는 날이 없다. 따라서 문제를 잘 정리하고 해결해서 기록해놓는게 정말 중요할 것 같다.