🔔 [관련 정리 리스트]
- React Quill 1-에디터 사용
- React Quill 2-이미지처리(편집중/참고만)
- React Quill 3-이미지처리(편집완료/사용)
- React Quill 4-이미지 리사이즈
지난번엔 에디터 작성, 이미지 치환, 이미지 리사이즈 까지 모두 적용해보았다.
기존 작성에 사용했던 컴포넌트에 수정 로직을 추가하여, 한 컴포넌트 안에서 조건에 따라 작성, 수정 로직을 각각 돌게 하고자 한다.
수정을 하려면 2가지 변경이 필요했다.
첫번째는 기존 이미지 치환(base64->URL) 코드 수정,
두번째로는 기존 작성하는 페이지 수정이 필요했다.
1. 기존 이미지 치환(base64->URL) 코드 수정
일단 아래는 기존 에디터 이미지 치환에 사용하는 커스텀 Hook이다.
기존에는 모든 이미지의 치환이 이루어졌다. 하지만 수정 로직 추가에 따라 수정된 이미지(URL)가 있을 경우 해당 로직을 돌지 않게하는 코드를 추가해야했다.
따라서 아래와 같이 진행하였다.
1. 기존 코드에서 isEdit 이란 props를 추가해서 받고,
2. while문 안에 아래 코드를 추가하여 조건(수정 조건: isEdit이 true이면서, URL이 이미 있는 경우는 base64->URL치환이 필요없기 때문에 넘어가도록 설정함)에 해당할 경우는 아래 코드가 실행되지 않게 한다.
* continue 문을 통해 해당 조건일 경우는 현재 반복을 그냥 넘어가고, 루프의 다음 반복(조건이 아닌 경우)을 진행
if (isEdit && result.startsWith('https://')) {
continue;
}
커스텀 Hook 전체 코드
* 1, 2만 추가함
import { useState } from 'react';
import axios from 'axios';
//Quill 이미지 치환
export default function useQuillImageReplacement() {
const [urlArray, setUrlArray] = useState<string[]>([]);
//*1. isEdit: props 추가
const replaceImages = async (content: string, isEdit: boolean) => {
const srcArray: string[] = [];
const gainSource = /(<img[^>]*src\s*=\s*[\"']?([^>\"']+)[\"']?[^>]*>)/g;
let endContent = content;
while (gainSource.test(content)) {
const result = RegExp.$2;
//*2. 추가/수정이면서 이미 URL 있는 건 아래 실행문 안되게 설정(작성시에만 아래 실행)
if (isEdit && result.startsWith('https://')) {
continue;
}
srcArray.push(result);
}
for (let i = 0; i < srcArray.length; i++) {
const result = srcArray[i];
const byteString = atob(result.split(',')[1]);
const ab = new ArrayBuffer(byteString.length);
const ia = new Uint8Array(ab);
for (let j = 0; j < byteString.length; j++) {
ia[j] = byteString.charCodeAt(j);
}
const blob = new Blob([ia], { type: 'image/jpeg' });
const file = new File([blob], `image-${i}.jpg`);
const formData = new FormData();
formData.append('files[]', file);
try {
const config = { header: { 'content-type': 'multipart/form-data' } };
//TODO: API연동(urlArray에 저장하기)
/* const response = await axios.post('/api/board/uploadImgFolder', formData, config);
if (response.data.success) {
setUrlArray(response.data.url);
endContent = endContent.replace(srcArray[i], response.data.url[i]);
} */
// 더미 데이터(테스트용)
const dummyUrl = [ 'https://img1.daumcdn.net/thumb/R1280x0.fjpg/?fname=http://t1.daumcdn.net/brunch/service/user/cnoC/image/66LHXQZY2bFLKR7SEO_KJjOnX6M',
'https://cdn.playforum.net/news/photo/202210/202392_18836_2310.jpg'];
setUrlArray(dummyUrl);//TODO: 서버에서 받는 S3 url로 추후 변경
endContent = endContent.replace(srcArray[i], dummyUrl[i]);
} catch (error) {
console.log('이미지 업로드 실패', error);
}
}
return endContent;
};
return { urlArray, replaceImages};
};
2. 작성페이지 (커스텀 Hook사용하기)
* 1, 2-1,2-2만 추가함
import { useParams } from 'react-router';
function NoticePageEdit({ lists, invoiceMaster,isEdit }: FormProps) {
const { id } = useParams(); //TODO:수정페이지 id에 따라 기존 값 api 가져오기
const { replaceImages,endContent } = useQuillImageReplacement();
..
//에디터
const [content, setContent] = useState(isEdit?data.content:'');//*2-1.수정일 경우 기존값으로 초기값설정
//완료 버튼 누를 시 실행되는 함수에 적용
const handlerCreate = async(values: any) => {
const updatedContent = await replaceImages(content,isEdit);//*1. 추가:isEdit props 전달
const totalValue = { ...values, content: updatedContent };
//console.log(totalValue, 'totalValue---');
};
...
return (
<Formik
initialValues={{
status: isEdit ? data.status : '', //*2-2.수정일 경우 기존값으로 초기값설정
title: isEdit ? data.title : ''
}}
validationSchema={validationSchema}
onSubmit={(values) => {
handlerCreate(values);
}}
>
위와 같이 설정한 후 route 관련 코드에서 같은 작성 컴포넌트에 props를 다르게 전달하여 작성, 수정페이지를 구분하였다.
{
path: 'create',
element: <NoticePageEdit isEdit={false} />
},
{
path: 'edit/:id',
element: <NoticePageEdit isEdit={true} />
}
결과 화면
해당 결과 수정페이지에서는 아래와 같이 기존 값을 초기값으로 잘 가져온다.(작성페이지에서는 빈 값)