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

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

목표

프로젝트에서 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
화이팅
post-custom-banner

0개의 댓글