ssr시 에디터 적용(dynamic import)

KIP·2022년 5월 22일
0


처음 에디터 사용 시 났던에러,
살펴보면 리액트의 버전(나의 경우 18.1)이 quill에디터와 맞지 않다고 나온다.
2가지 방법

  1. quill의 베타버전을 사용한다(npm i react-quill@beta)
  2. 리액트의 버전을 다운그레이드한다. (npm install --save react@^16.14.0 react-dom@16.14.0)

베타 버전의 경우 나온 정보가 많지 않거나 아직 많은 사용자들이 쓰지않았다고 판단하여 옛 버전으로 다운그레이드를 한 후 진행했다.

그렇게 에디터를 사용할 때 생긴 2번째 문제 (next의 사용 시)

window is not defined, document is not defined
에디터는 모두 브라우저의 객체를 참조하고 있다. 이런 라이브러리들의 경우 next.js의 ssr 옵션을 끄고 참조를 진행해야한다.
next.js는 디폴트로 각 페이지들은 빌드시 미리 렌더한다(pre-render) 이때 실행환경은 node이므로, client-side에서만 사용되는 라이브러리의 코드들은 ssr 옵션을 끄고 동적으로 참조해야한다.(dynamic)

처음 페이지를 줄이기 위해서 페이지 내부에 글쓰기 버튼을 누르면 페이지가 아닌 컴포넌트만을 이동시켜 글쓰기 폼을 생성하려 했는데,
에디터를 쓰다보니 dynamic으로 ssr을 false시켜 에디터를 불러오니 내가 생각한 그림이 그려지지 않았다.

-> 에디터를 쓰기전에는 로직이 문제 없었는데 에디터를 도입하고 난 후 생긴 문제 (글쓰기를 누르기 전부터 에디터가 나와버린다. 그냥 글을 생성하는 페이지를 다시 만들기로..

----추가 수정사항
다른 사람의 코드를 따라했는데, 어떤식으로 동작이 되는지는 정확하게 파악하지 못했다. ref관련 이슈가 나서 dynamic import로 ssr:false를 한 것까진 이해를 했는데, 부분별로 나눠서 좀 알아보고자 한다.

공지사항 글을 생성하는 페이지이고 처음 Dynamic import쪽
const ReactQuill = dynamic(async () => { const { default: RQ } = await import('react-quill'); return function comp({ forwardedRef, ...props }) { return <RQ ref={forwardedRef} {...props} />; }; }, { ssr: false });

quilleditor의 formats 부분: 필요한 기능들만 넣고 나머지는 제거를 한 상태
const formats = [ "header", "font", "size", "bold", "italic", "underline", "strike", "blockquote", "list", "bullet", "indent", "link", "image", "video", ];

에디터 쪽

const ReactQuillContainer = ({ description, setDescription,title,setTitle, onChange}) =>{
  const quillRef = useRef();
  const dispatch = useDispatch();
  const {user} = useSelector((state) => state.user)

 if(quillRef.current){
  description = quillRef.current.state.value
   console.log('hi')
 }else{
   console.log('bi')
 }

  const onSubmit = () =>{
    console.log(quillRef.current.state.value)
    const value =document.getElementsByName('title')
    console.log(value[0].value)
    if(  user.userEmail || quillRef.current.state.value){
      const data = {    
        userEmail: user.userEmail,
        notTitle: value[0].value,
        notContent: quillRef.current.state.value
      }
       dispatch({ 
        type: NOTICE_CREATE_REQUEST,
        data: data 
      }
    )}
    }
    ```
  const imageHandler = (e) => {
  console.log(quillRef.current.state)
  console.log(quillRef.current.getEditor())
  console.log(quillRef.current.isDelta)
  console.log(quillRef.current.props.value)
  console.log(quillRef.current.state)
  console.log(typeof quillRef.current.state.value)
    const input = document.createElement('input')
    input.setAttribute('type', 'file');
    input.setAttribute('accept', 'image/*');
    document.body.appendChild(input);
    input.click(e);
    input.onchange = async(e) => {
      console.log(e)
      console.log(e.preventDefault)
      const imageFormData = new FormData();
      [].forEach.call(e.target.files,(files) =>{
        imageFormData.append('files',files)
      }); 
     const result = await axios.post
     
     (`http://localhost:8080/api/file/upload`, imageFormData)
      console.log(result)
      dispatch({
        type: IMAGE_PREVIEW_REQUEST,
        data: result.data[0]
      })

      console.log(quillRef.current.state)

 const range = quillRef.current.getEditorSelection();
      quillRef.current.getEditor().insertEmbed(range.index, 'image', result.data[0])
      quillRef.current.getEditor().setSelection(range.index + 1);
      document.body.querySelector(':scope > input').remove()
    };
  }
  const modules = useMemo(() => ({
    toolbar: {
      container: [
        [{ 'header': [1, 2, false] }],
        ['bold', 'italic', 'underline','strike', 'blockquote'],
        [{'list': 'ordered'}, {'list': 'bullet'}, {'indent': '-1'}, {'indent': '+1'}],
        ['link', 'image'],
        ['clean']
      ],
      handlers: { image: imageHandler }
    }
  }), []);
  return (
    <AppLayout>
          <Form
    onFinish={onSubmit}>
      <label htmlFor="">제목:</label>
      <input type="text" name="title" id="" value={title} onChange={setTitle}/>
         <ReactQuill
      forwardedRef={quillRef}
      placeholder="본문을 입력하세요..."
      modules={modules}
      formats={formats}
      value={description || ""}
      onChange={setDescription}
    />
    <Button htmlType='submit'>전송</Button>
    </Form>
    </AppLayout>

0개의 댓글