App컴포넌트 내에서 SiedBar, EditFrame 두 개의 컴포넌트를 각각 페이지로 사용하고자 했으나, 두 영역이 동시에 보여지는 구조이고, 한 컴포넌트의 이벤트 발생 시 다른 컴포넌트가 재생성되기 때문에 페이지로 사용 시 부드러운 화면 전환을 할 수 없었다. (페이지로 사용한다는 것은 초기 비동기 작업까지 포함한다는 것)
그렇기에 비동기 작업을 app에게 위임했다. 그러나 이럴 경우 페이지로 사용한다고 할 수 없기 때문에 컴포넌트 역할에 대한 통일성을 해쳐서 고민이다.
자세한 고민 과정..
페이지를 이동할 때 컴포넌트가 생성되게 했다.
엄연히 따지면 App컴포넌트가 한 페이지고 Sidebar와 EditFrame은 자식 컴포넌트지만 나는 각각 두 영역을 페이지로 사용하고 싶었기 때문이다.
왜냐하면 두 영역에 대한 로직을 각 App에 합쳐서 작성하는 것이 아니고 각 컴포넌트에 몰아넣고 싶었다.
그래서 각 페이지에 대한 데이터를 App에서 부르고, 상태에 저장해서 EditFrame을 리렌더링하는게 아닌 EditFrame자체에서 데이터를 부르고 url변경될 때마다 새롭게 생성되도록(데이터를 부르도록)했다.
하지만 이 경우 문제가 있었다..
페이지가 외부 데이터를 가져와 렌더링되어야 할 경우에 빈 데이터로 먼저 렌더링을 한 후, 데이터가 불려지면 결과 값을 사용해 리렌더링을 하도록 구현했는데,
이럴 경우 문서가 바뀔 때마다 매번 빈 값으로 먼저 렌더링이 되고나서 실제 데이터로 렌더링되기 때문에 부드럽게 변경이 안되고 깜빡였다.. 기능상으론 문제없지만 사용성이 안 좋았다.
아예 전체 페이지 자체가 바뀌는거면 상관없지만 하지만 노션같은 경우에는 한 페이지에 sidebar, editor 두 영역이 있고, url이 바뀌면 editor영역만 바뀌기 때문이다.
결국에는 url이 변경될 때마다 App컴포넌트에서 데이터를 부르고, 데이터가 받아지면 그대로 EditFrame컴포넌트에 전달해 생성되게 했다.
async route(target) {
const { pathname } = window.location;
if (pathname === '/') {
new EditFrame(target, { id: '', title: '', content: '' });
return;
}
if (pathname.indexOf('/pages/') === 0) { // 문서 페이지 이동 시마다
const [, , pageId] = pathname.split('/');
const { title, content } = await getDocument(pageId); // 데이터 불러오고
new EditFrame(target, { // 받은 데이터를 전달해 생성
id: pageId,
title,
content,
onUpdatePageList: () => {
this.Sidebar.fetch();
},
});
return;
}
}
하지만 이 방법이 과연 맞는 것일지 모르겠다.
차라리 App컴포넌트를 전체 페이지로 보고 Sidebar, EditFrame의 데이터 로직을 전부 App컴포넌트에서 관리하는게 맞는 방법인지 고민된다. 두 컴포넌트가 상호작용 할 일이 있을 것이기 때문이다.
각 컴포넌트의 데이터 로직을 훅으로 분리하든가, 전역상태로 관리하든가.. 생각을 더 해봐야겠다.