프로젝트를 진행하던 중 사이드바에서의 동작이 에디터를 제어하거나 그 반대의 상황일 때 porps로 상태를 전달하기엔 적어도 3depth의 컴포넌트를 거쳐야 합니다. 이때 코드가 복잡해지면 상태를 관리하기 힘들어지는 props drilling 문제가 생기는데 이를 해결하기 위해 중앙 집중식 상태 관리를 적용했습니다.
이전에 작성한 Vanilla JS로 중앙 집중식 상태 관리 구현하기를 이용했습니다.
저는 총 2개의 store를 만들어 관리했습니다.
1. 사이드바의 전체 페이지들을 저장하는 store
2. 현재 편집하려는 페이지의 Id를 저장하는 store
사이드바의 전체 페이지들을 저장하는 store
store_pages.store.js
store는 다음과 같이 만들어주었습니다.
import { createStore } from "@core";
import { getItem } from "@stores";
const initialState = {
pages: {
pages: [],
openedDetail: new Set(getItem("openedDetail", [])),
selected: getItem("selected") || null,
},
};
export const SET_PAGES = "SET_PAGES";
export const store_pages = createStore((state = initialState, action = {}) => {
switch (action.type) {
case "SET_PAGES":
return { ...state, pages: { ...state.pages, ...action.payload } };
default:
return state;
}
});
export const setPAGES = (payload) => ({ type: SET_PAGES, payload });
observe 하고싶은 함수 subscribe
이 store_pages의 경우 상태 변경이 일어났을 때 사이드바에서 전체 페이지를 보여주는 컴포넌트의 리렌더링이 필요합니다. 따라서, 해당 위치에서 observe 하고싶은 함수를 subscribe 해줍니다.
export default class SideBarPages extends Component {
setup() {
store_pages.dispatch(
setPAGES({
pages: this.props,
})
);
store_pages.subscribe(() => {
this.render();
});
this.data = new Data();
this.hoveredElementId = null;
}
...
상태 변경의 종류
store_pages의 상태가 변경되는 경우는 다음과 같습니다.
사이드바 페이지에서
- 페이지를 추가/삭제할 때
- 페이지를 토글할 때
- 페이지를 선택할 때
사이드바 헤더에서
- 페이지를 추가할 때
Editor에서
- 문서를 수정했을 때 (목록이 업데이트 되어야함)
적절한 위치에서 dispatch를 이용해 각각 상태를 변경해줍니다.
store_pages.dispatch(
setPAGES({ pages, openedDetail: tempOpenedDetail, selected })
);
//SideBarPages.js
export default class SideBarPages extends Component {
...
setEvent() {
this.addEvent("click", ".sidebar__pages--detail-click", async (e) => {
...
switch (action) {
case "toggle":
const tempOpenedDetail = setOpenedDetail(action, id);
store_pages.dispatch(
setPAGES({
openedDetail: tempOpenedDetail,
})
);
break;
}
...
}
현재 편집하려는 페이지의 Id를 저장하는 store
다음과 같이 만들어주었습니다.
import { createStore } from "@core";
import { getDocumentId } from "@/router";
const initialState = {
documentId: getDocumentId(),
};
export const SET_ID = "SET_ID";
export const store_documentId = createStore(
(state = initialState, action = {}) => {
switch (action.type) {
case "SET_ID":
return { ...state, documentId: action.payload };
default:
return state;
}
}
);
export const setID = (payload) => ({ type: SET_ID, payload });
observe 하고싶은 함수 subscribe
이 store_documentId의 경우 선택한 페이지가 달라질 때 해당 Id를 관리해 Editor에서 제목과 내용을 Id마다 다르게 렌더링 해줘야합니다.
export default class Editor extends Component {
setup() {
this.data = new Data();
this.$editorTotalContents = this.$target.querySelector(".editor__title");
this.editorTotalContents = null;
this.current_documentId = null;
this.state = {
title: "",
content: "",
};
store_documentId.dispatch(setID(getDocumentId()));
store_documentId.subscribe(() => {
this.render();
});
}
...
상태 변경의 종류
store_documentId의 상태가 변경되는 경우는 다음과 같습니다.
사이드바 페이지에서
- 페이지를 추가/삭제할 때
- 페이지를 선택할 때
사이드바 헤더에서
- 페이지를 추가할 때
- 페이지를 이동할 때
이 역시 적절한 위치에서 dispatch를 이용해 각각 상태를 변경해줍니다.
store_documentId.dispatch(setID(getDocumentId()));
//SideBarPages.js
export default class SideBarPages extends Component {
...
setEvent() {
...
this.addEvent("click", ".sidebar__pages--detail-click", async (e) => {
...
switch (action) {
...
case "remove":
await executeWithTryCatch(async () => {
await this.data.deleteDocumentStructure(id);
push(`/main`);
store_documentId.dispatch(setID(getDocumentId()));
getPages("remove", id);
}, "Error remove document structure SideBarPages");
break;
...
}
'프로젝트 > Vanilla JS 문서편집기' 카테고리의 다른 글
[Vanilla JS 문서편집기 설명 및 개선] 8. Rich한 에디터 만들기(2) (1) | 2024.09.08 |
---|---|
[Vanilla JS 문서편집기 설명 및 개선] 7. Rich한 에디터 만들기(1) (0) | 2024.09.06 |
[Vanilla JS 문서편집기 설명 및 개선] 5. VirtualDOM처럼 렌더링하기 (1) | 2024.08.29 |
[Vanilla JS 문서편집기 설명 및 개선] 4. 컴포넌트 템플릿 만들기 (0) | 2024.08.29 |
[Vanilla JS 문서편집기 설명 및 개선] 3. 사이드바 렌더링 최적화 및 성능 비용 절감 (0) | 2024.08.21 |