돌려돌려 돌림판~! (4) - Next.js로 전환

김영현·2024년 6월 12일
1

돌려돌려 돌림판

목록 보기
4/5

Next로의 전환

바닐라 JS의 숙련도를 키우기 위하여 바닐라JS로 제작한 프로젝트인 돌려 돌려 돌림판!
이제 Next도 공부하고있는데, 뭘 만들까 고민하다가 아예 바닐라JS로만든 프로젝트를 옮겨보기로 했다. 마이그레이션은 아니고 포팅 정도?
그리고 하다보니 컴포넌트 하나하나 만드는게 너무 귀찮았다. 특히 DOM조작이 많아지니 코드가 복잡해져 헷갈리기도 했다😥

이래서 프레임워크를 사용하는구나?

하다가 마주친 문제를 하나씩 훑어보자

ContentEditable 포커스 버그 수정해보기

마우스로 그림판에서 그렸더니 심각하구먼? 😮
아무튼 대충 이런 구조로 컴포넌트를 설계했다. 바닐라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할 일이 없기에 전역상태를 사용하는 로직을 넣어줌.

요런식으로다가...일단 프로젝트를 더 진행시키고 폴더구조를 변경해봐야겠다.

profile
모르는 것을 모른다고 하기

0개의 댓글