NextJs - react-simplemde-editor 이슈,해결

dev-won·2023년 4월 22일
0
post-thumbnail

목표

프로젝트에서 Nextjs를 사용하고 있고 react-simplemde-editor를 이용하여 Editor component를 만들고, props데이터로 Preview 기능을 옵셔널하게 바꾸려고 하였습니다.

문제 발생

  1. import 후 렌더링시 ReferenceError: navigator is not defined 오류 발생
  2. useRef return {retry: ƒ}
  3. Dom api를 활용하여 부모, 형제 Node를 찾을 수 없음

1. import 후 렌더링시 ReferenceError: navigator is not defined 오류 발생

react-simplemde-editor GibHub의 문서를 보고 코드를 작성하였지만 문제가 바로 발생하였다. error 내용에 This error happened while generating the page 이 부분을 보고, Nextjs가 ssr이니 서버에서 페이지 생성중 문제가 발생한거 같아 Nextjs 관련해서 찾아 보니 쉽게 찾을 수 있었습니다.

import dynamic from 'next/dynamic'

const SimpleMdeReact = dynamic(() => import('react-simplemde-editor'), {
  ssr: false,
});

2. useRef return {retry: ƒ}

다른 라이브러리의 경험을 살려 react-simplemde-editor 컴포넌트에 useRef를 사용하여 객체 정보를 가져오려고 하였다. 하지만 계속 {retry: ƒ} 값만 주고 있었습니다.

const SimpleMdeReact = dynamic(() => import('react-simplemde-editor'), {
  ssr: false,
});

export const Editor = () => {
  const editor = useRef(null);

  console.log(editor.current); // {retry: ƒ}
  return <SimpleMdeReact ref={editor} />;
};

여기에 관련해서 찾아보니 forwardRef 사용해서 ref를 전달할 수 있게 적용이 필요하다고 하였다. 하지만 SimpleMdeReact code를 직접 확인해보니 이미 적용이 되어있었습니다. 그외에 stackoverflow에 관련 내용을 찾아보니 dynamic import 과정에서 직접 props로 내려주는 답변을 보았다.

const EditorWarrap = dynamic(
  async () => {
    const { SimpleMdeReact } = await import('react-simplemde-editor');

    return ({ forwardedRef, ...props }) => (
      <SimpleMdeReact ref={forwardedRef} {...props} />
    );
  },
  {
    ssr: false,
  }
);

export const Editor = () => {
  const editor = useRef(null);

  useEffect(() => {
    if (!editor.current) return;

    console.log(editor.current.parentElement);
  });

  return <EditorWarrap forwardedRef={editor} />;
};

위 코드처럼 진행하면 문제없이 접근을 할 수 있다. dynamic import를 사용한다면 위 코드처럼 import하는 과정에서 직접 전달하지 않고 import 할 경우 완전한 독립환경이 생겨 접근할 수 없다고한다.

3. Dom api를 활용하여 부모, 형제 Node를 찾을 수 없음

react-simplemde-editor에서 반환하는 instance를 통하여 istogglePreview()라는 메소드를 실행하니 오류가 발생하였습니다.

이번 오류에 대해서는 기능적인 오류인거 같아 어떻게 접근해야 할지 몰라 일단 에러가 어떻게 발생하는지 찾기 위해 디버깅을 해봤습니다.

1034번째 줄 cm.getWrapperElement().nextSibling코드가 실행된 후 null 데이터가 sidebyside 변수에 담겨져 있어서 에러가 발생하였습니다.

그리고 chrome 디버깅모드에서 local scope 변수를 찾아 볼 수있는데, 여기서 찾은 node들을 클릭해도 이동이 되지 않고 아래와 같이 현재 페이지에서 노드를 찾을 수 없습니다.라는 로그가 출력되었습니다.

이번 error도 2번 항목처럼 dynamic import로 가져온 component는 독립적인 scope 환경이라 접근이 안되는 느낌을 받았습니다.

code

const EditorWarrap = dynamic(
  async () => {
    const { SimpleMdeReact } = await import('react-simplemde-editor');

    return ({ forwardedRef, ...props }) => (
      <SimpleMdeReact ref={forwardedRef} {...props} />
    );
  },
  {
    ssr: false,
  }
);

export const Editor = () => {
  const [editor, setEditor] = useState();

  useEffect(() => {
    if (!editor) return;

    editor.togglePreview();
    // togglePreview는 정적 메소드라서 Type Error를 발생하지만 사용할 수는 이다.
  });

  return (
    <EditorWarrap
      getMdeInstance={(ins) => {
        if (!editor) setEditor(ins);
      }}
    />
  );
};

정리

위와 같은 모든 에러는 dynamic import를 하면서 발생하는 error이다.

이 문제점를 해결하면서 dynamic import를 할 때 모듈을 import하는것과 모듈을 import를 후 컴포넌트로 반환하는것 두개의 차이가 좀 이해가 안되어 이럴때 chatgpt 활용해 봤다.

const SimpleMdeReact = dynamic(() => import('react-simplemde-editor'), {
  ssr: false,
});

코드에서는 dynamic 함수의 첫 번째 인자로 import('react-simplemde-editor')를 전달하여 react-simplemde-editor 모듈을 반환합니다. 이 경우, SimpleMdeReact 컴포넌트가 로딩되는 시점은 해당 모듈이 불러와질 때입니다.

const EditorWarrap = dynamic(
  async () => {
    const { SimpleMdeReact } = await import('react-simplemde-editor');
    return ({ forwardedRef, ...props }) => (
      <SimpleMdeReact ref={forwardedRef} {...props} />
    );
  },
  { ssr: false }
);

코드에서는 dynamic 함수의 첫 번째 인자로 async 함수를 전달하여 SimpleMdeReact 컴포넌트를 불러오는 함수를 생성합니다. 이 함수는 로딩이 완료되면 SimpleMdeReact 컴포넌트를 반환하므로, 실제로 SimpleMdeReact 컴포넌트가 로딩되는 시점은 해당 함수가 실행될 때입니다.

코드 실행 차이로 인해 dom node를 못 찾는 거는 좀 이해가 안 되지만,두 코드의 실행 시점의 차이가 있다는 것은 알게 되었습니다.

결론으로 dynamic import로 가져온 모듈은 어떤 상태이길래 같은 모듈 내에 있는 형제 노드까지 찾지 못하는지 알고 싶습니다.

profile
화이팅

0개의 댓글

관련 채용 정보