
Today I Learn📖
- 자동 저장 편집기 만들기 (강의)
포스트 생성, 조회, 수정 서비스 제작시 필요한 API
- 편집 가능한 글 목록 불러오기: https://도메인/posts (GET 요청)
- 특정 게시글 불러오기: https://도메인/posts/{id} (GET 요청)
- 게시글 저장하기: https://도메인/posts (POST 요청)
- 게시글 수정하기: https://도메인/posts/{id} (PUT 요청)
별도의 저장 버튼을 누르지 않아도 자동으로 저장되는(서버와 싱크되는) 기능
-> url에 따른 라우팅 처리가 들어가는 것
게시글 에디터(편집기) 만드는 방법
먼저 textarea로 돌아가게 만들고, 그 후 에디터만 contenteditable로 업그레이드 시키는 방식을 추천 !
textarea
별도의 스타일을 넣을 수 없음, 스타일 입힌 거 자동으로 미리보기 안 됨
-> 마크다운 텍스트를 넣고, 그 텍스트를 파싱해서 미리보기 띄울 수는 있음
contenteditable
<div> 태그 안에 contenteditable="true" 넣으면 됨
-> 값을 사용할 때는 innerHTML을 써야함 (.value X)
서버에서 내래오는 스타일 값과 마크다운 문법이 달라서, 정규표현식을 통한 replace 혹은 if문 등으로 처리해줘야함
ex) 서버에서 내려오는 개행값은 \n 라서 textarea 에서도 개행이 \n. 하지만 contenteditable은 innerHTML을 쓰니까 <br>임
<div name="~~" contenteditable="true" ...> </div>
같은 이벤트가 계속 발생하는 경우에, 그 중 마지막 작업 이후 일정 시간동안 이벤트가 더 발생하지 않으면 이벤트 핸들러를 실행시킴
=> 불필요한 처리를 줄이기 위해 이벤트가 발생하는 동안은 실행 지연시킴
let timer = null; // 시간 재는 애
new Editor({
$target,
initialState: post,
onEditing: (post) => {
// setTimeout은 아이디값을 뱉기 때문에, 그 값의 존재여부 등으로 초기화 가능
if (timer !== null) clearTimeout(timer) // 타이머 초기화
timer = setTimeout(() => { // 0.5초 이후에 실행됨
setItem(TEMP_POST_SAVE_KEY, { // 0.5초 후에 로컬 스토리지에 저장
...post,
tempSaveDate: new Date()
})
}, 500) // 0.5초 지정
}
})
직접 만들어서 사용할 수 있는 이벤트 (필요하거나 자주 반복되는 기능 만들면 유용함)
// PostList.js
/*
* .dispatchEvent() 를 통해 이벤트 발생 시키기 (앞에 window 쓰면 전역적 사용 가능)
* new CustomEvent로 커스텀 이벤트 생성 가능
* 둘이 한번에 쓰면 정의하자마자 사용 가능
*/
window.dispatchEvent(new CustomEvent('route-change', { // 파라미터 => (이벤트 이름, {전달할 값})
detail: { // detail 안에 전달할 값 정의
nextUrl: `/post/${id}`
}
}))
//App.js
window.addEventListener('route-change', (e) = { // 정의한 이름으로 이벤트 사용
const { nextUrl } = e.detail // e.detail로 꺼내올 수 있음
if (nextUrl) {
history.pushState(null, null, nextUrl)
this.route()
}
})
/* 위 과정에서 'route-change'를 자주 쓰면 오타로 인한 에러 발생 위험이 있기 때문에 저것들을 모아서 한 파일로 만들면 더 좋음 */
// router.js
const ROUTE_CHANGE_EVENT_NAME = 'route-change' // 오타로 인한 에러 방지를 위해 선언
export const initRouter = (onRoute) => { // 커스텀 이벤트 감지해 url 변경 & 화면 렌더링
window.addEventListener(ROUTE_CHANGE_EVENT_NAME, (e) => {
const { nextUrl } = e.detail
if (nextUrl) {
history.pushState(null, null, nextUrl)
onRoute()
}
})
}
export const push = (nextUrl) => {
window.dispatchEvent(new CustomEvent('route-change', { // 커스텀 이벤트 생성
detail: {
nextUrl
}
}))
}
// App.js
.
.
.
initRoute(() => this.route())
}
// PostList.js
import { push } from "./router.js"
.
.
.
if ($li) {
const { id } = $li.dataset
push(`/post/${id}`) // push 함수를 통해 커스텀 이벤트에 요청 -> 이벤트 생성됨 -> initRouter가 감지해 작동
}
에디터 만드는 도구는 textarea밖에 몰랐는데, 새로운 도구를 알게됐다 ㅎㅎ
노션의 자동 저장 방식이 궁금했었는데 디바운스를 이용하면 구현 할 수 있다는 것을 배웠고, 새로운 개념인 커스텀 이벤트에 대해서도 학습할 수 있었다. 커스텀 이벤트를 이용하면 컴포넌트들끼리의 의존성을 더 줄일 수 있을 것 같다 !
앞으로 진행될 노션클로닝 과제를 수행하는데 있어서 큰 힘이 될 것 같다 🥹