React-quill 라이브러리를 통해 에디터 기능을 구현하였고, 이 중 이미지를 처리하는 함수를 만들어야 된다. 그 이유로는 그냥 이미지를 넣어주면 base64로 변환된 이미지가 너무 길어서 서버에 저장되지 않는 문제가 발생하기 때문이다.
따라서 이미지 태그의 src에 base64 대신 url을 넣어주어야 한다.
// 이미지 처리를 하는 핸들러
const imageHandler = () => {
// 1. 이미지를 저장할 input type=file DOM을 만든다.
const input = document.createElement("input");
// 속성 써주기
input.setAttribute("type", "file");
input.setAttribute("accept", "image/*");
input.click(); // 에디터 이미지버튼을 클릭하면 이 input이 클릭된다.
// input이 클릭되면 파일 선택창이 나타난다.
// input에 변화가 생긴다면 = 이미지를 선택
input.addEventListener("change", async () => {
if (input.files && input.files.length > 0) {
const file = input.files[0];
// multer에 맞는 형식으로 데이터 만들어준다.
const formData = new FormData();
formData.append("file", file); // formData는 키-밸류 구조
// 백엔드 multer라우터에 이미지를 보낸다.
try {
const result = await axios.post("/api/upload", formData, {
headers: {
"Content-Type": "multipart/form-data", // 중요: 멀티파트(form-data) 형식으로 보내기 위해 헤더 설정
},
});
const IMG_URL = result.data;
// 이 URL을 img 태그의 src에 넣은 요소를 현재 에디터의 커서에 넣어주면 에디터 내에서 이미지가 나타난다
// src가 base64가 아닌 짧은 URL이기 때문에 데이터베이스에 에디터의 전체 글 내용을 저장할 수있게된다
// 이미지는 꼭 로컬 백엔드 uploads 폴더가 아닌 다른 곳에 저장해 URL로 사용하면된다.
// 이미지 태그를 에디터에 써주기 - 여러 방법이 있다.
const editor = quillRef.current.getEditor(); // 에디터 객체 가져오기
// 1. 에디터 root의 innerHTML을 수정해주기
// editor의 root는 에디터 컨텐츠들이 담겨있다. 거기에 img태그를 추가해준다.
// 이미지를 업로드하면 -> 멀터에서 이미지 경로 URL을 받아와 -> 이미지 요소로 만들어 에디터 안에 넣어준다.
// editor.root.innerHTML =
// editor.root.innerHTML + `<img src=${IMG_URL} /><br/>`; // 현재 있는 내용들 뒤에 써줘야한다.
if (editor) {
// 2. 현재 에디터 커서 위치값을 가져온다
const range = editor.getSelection();
// 가져온 위치에 이미지를 삽입한다
editor.insertEmbed(range.index, "image", IMG_URL[0]);
editor.setSelection(range.index + 1);
}
} catch (error) {
console.log("실패했어요ㅠ");
}
}
});
};
이 코드가 이미지를 처리하는 함수로 자세한 설명은 주석으로 달아놓았으니 생략하겠다.
const result = await axios.post("/api/upload", formData, {
headers: {
"Content-Type": "multipart/form-data", // 중요: 멀티파트(form-data) 형식으로 보내기 위해 헤더 설정
},
});
이 코드를 통해서 이미지를 백엔드 서버로 보내주고 url을 받아준다.
handlers: {
// 이미지 처리는 우리가 직접 imageHandler라는 함수로 처리할 것이다.
image: imageHandler,
},
이 코드를 react-quill 라이브러리를 사용할때 필요한 modules 안에 넣어주어야되고, useMemo() 를 사용하여 랜더링 문제를 해결해 주어야 한다.
이미지 처리 방식은 벨로그에 많이 나와있으므로 이정도까지 하겠다.
return (
<div>
<ReactQuill
ref={quillRef}
modules={modules}
formats={formats}
placeholder="여러분의 경험을 자유롭게 적어주세요."
className="h-[1000px] outline-none"
theme="snow"
value={value}
onChange={setValue}
/>
{/* <div>{value}</div> */}
<div dangerouslySetInnerHTML={{ __html: value }} />
{/* Display the 'value' state */}
</div>
);
또한 백엔드에 post내용을 전달해줄때
<div dangerouslySetInnerHTML={{ __html: value }} />
이 코드가 꼭 필요한데 그 이유로는
dangerouslySetInnerHTML은 브라우저 DOM에서 innerHTML을 사용하기 위한 React의 대체 방법입니다. 일반적으로 코드에서 HTML을 설정하는 것은 사이트 간 스크립팅 공격에 쉽게 노출될 수 있기 때문에 위험합니다. 따라서 React에서 직접 HTML을 설정할 수는 있지만, 위험하다는 것을 상기시키기 위해 dangerouslySetInnerHTML을 작성하고 __html 키로 객체를 전달해야 합니다.
라고 공식문서에 잘 나와 있다.