프로젝트에서 Nextjs를 사용하고 있고 react-simplemde-editor
를 이용하여 Editor component를 만들고, props데이터로 Preview
기능을 옵셔널하게 바꾸려고 하였습니다.
- import 후 렌더링시
ReferenceError: navigator is not defined
오류 발생- useRef return
{retry: ƒ}
- Dom api를 활용하여 부모, 형제 Node를 찾을 수 없음
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,
});
다른 라이브러리의 경험을 살려 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 할 경우 완전한 독립환경이 생겨 접근할 수 없다고한다.
react-simplemde-editor
에서 반환하는 instance를 통하여 istogglePreview()
라는 메소드를 실행하니 오류가 발생하였습니다.
이번 오류에 대해서는 기능적인 오류인거 같아 어떻게 접근해야 할지 몰라 일단 에러가 어떻게 발생하는지 찾기 위해 디버깅을 해봤습니다.
1034번째 줄 cm.getWrapperElement().nextSibling
코드가 실행된 후 null
데이터가 sidebyside 변수에 담겨져 있어서 에러가 발생하였습니다.
그리고 chrome 디버깅모드에서 local scope 변수를 찾아 볼 수있는데, 여기서 찾은 node들을 클릭해도 이동이 되지 않고 아래와 같이 현재 페이지에서 노드를 찾을 수 없습니다.
라는 로그가 출력되었습니다.
이번 error도 2번 항목처럼 dynamic import로 가져온 component는 독립적인 scope 환경이라 접근이 안되는 느낌을 받았습니다.
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로 가져온 모듈은 어떤 상태이길래 같은 모듈 내에 있는 형제 노드까지 찾지 못하는지 알고 싶습니다.