바닐라 JS의 숙련도를 키우기 위하여 바닐라JS로 제작한 프로젝트인 돌려 돌려 돌림판!
이제 Next도 공부하고있는데, 뭘 만들까 고민하다가 아예 바닐라JS로만든 프로젝트를 옮겨보기로 했다. 마이그레이션은 아니고 포팅 정도?
그리고 하다보니 컴포넌트 하나하나 만드는게 너무 귀찮았다. 특히 DOM조작이 많아지니 코드가 복잡해져 헷갈리기도 했다😥
이래서 프레임워크를 사용하는구나?
하다가 마주친 문제를 하나씩 훑어보자
마우스로 그림판에서 그렸더니 심각하구먼? 😮
아무튼 대충 이런 구조로 컴포넌트를 설계했다. 바닐라JS로 했던 걸 그대로 옮겨오며 전역 상태로 바꾼 것뿐임.
이제 EditableDive
컴포넌트에선 돌림판 상태값 프로퍼티중 하나인 text
를 받아와 아래와 같이 업데이트해주었다.
const EditableDiv = ({ text, onInput }: EdtiableDiv) => {
return (
<div
onInput={(event) =>
onInput((event.target as HTMLDivElement).textContent || "")
}
contentEditable
>
{text}
</div>
);
};
그런데 이렇게 업데이트 하니, 한 글자 쓸 때마다 div
의 포커싱이 풀리는 현상 발생.
예전에 노션 클론했을때도 그렇고, 바닐라JS로 만든 돌림판에서는 상태와 연관짓지 않고 업데이트하여 버그를 수정했었다.
그렇다면 리액트에서도 비슷하게 고칠 수 있지 않을까?
=> 비제어 컴포넌트방식을 사용하면 된다.
원래 사용하던 돌림판 상태인 text
를 바로 사용하는 게 아닌, 비제어 방식으로 사용한다.
const EditableDiv = ({ text, onInput }: EdtiableDiv) => {
const divRef = useRef<HTMLDivElement>(null);
useEffect(() => {
if (divRef.current && text) {
divRef.current.textContent = text;
}
}, [text]);
return (
<div
onInput={(e: React.ChangeEvent<HTMLDivElement>) => {
onInput(e.target.textContent || "");
divRef.current && (divRef.current.textContent = e.target.textContent);
}}
contentEditable
ref={divRef}
/>
);
};
ref
로 참조를 걸어두고 직접 DOM 조작을 하듯 값을 변경한다.
이렇게 되면 상태가 업데이트된 것이 아니기에 포커싱이 풀리지 않음.
해결!
Next는 처음인지라 폴더구조가 살짝 어려웠다. 특히 돌림판은 페이지가 단 하나기에 파일기반 라우팅을 사용할 일도 없었기에...
그리고 공식 튜토리얼에서 제공했던 폴더구조가 Best라고 생각해 베껴보았다.
공식 튜토리얼에서 사용하는 폴더구조는 대략 이렇다. 특히 ui폴더가 신기하다.
각 페이지마다 대응되는 ui폴더가 있고, 내부 컴포넌트를 자세히 들여다보면 데이터 fetching을 하고있다.
ui인데 왜 fetching을 하고있을까 살짝 의문이지만, 공식문서니까 그대로 따라해봄...다만돌림판은 fetching할 일이 없기에 전역상태를 사용하는 로직을 넣어줌.
요런식으로다가...일단 프로젝트를 더 진행시키고 폴더구조를 변경해봐야겠다.