🤍 전 강의 25% 할인 중 🤍

2024년 상반기를 돌아보고 하반기에도 함께 성장해요!
인프런이 준비한 25% 할인 받으러 가기 >>

  • 카테고리

    질문 & 답변
  • 세부 분야

    풀스택

  • 해결 여부

    미해결

quill editor 사용 이미지 업로드 질문 있습니다.

22.01.29 01:14 작성 조회수 1.31k

0

/back/routes/post

const router = require('express').Router();
const multer = require('multer');
const fs = require('fs');
const path = require('path');
 
try {
fs.accessSync('uploads');
} catch (error) {
console.log('uploads 폴더가 없으므로 생성합니다.');
fs.mkdirSync('uploads');
}
 
const upload = multer({
storage: multer.diskStorage({
destination: function (req, file, done) {
done(null, 'uploads/');
},
// 이미지.png
filename: function (req, file, cb) {
const ext = path.extname(file.originalname); // 확장자 추출(.png)
const basename = path.basename(file.originalname, ext); // 이미지
done(null, basename + new Data().getTime() + ext); // 이미지20210124.png
},
}),
limits: { fileSize: 20 * 1024 * 1024 }, // 파일크기: 20MB
}); // 지금은 하드디스크에 저장하지만 AWS 배포 시 storage 옵션만 S3 서비스로 갈아끼울 예정

// POST /post/images
router.post('/images', isLoggedIn, upload.array('image'), (req, res, next) => {
console.log(req.files); // 업로드가 어떻게 됬는지 정보들이 담겨있음
res.json(req.files.map((v) => v.filename)); // 어디로 업로드 됬는지에 대한 파일명들을 프론트로 전송
}); // 먼저 파일명만 return 해준다. -> v.filename, 추후 배포 시 이미지는 지우지 않는다.(자산이다)

백엔드에서 multer를 이용해 이미지 업로드 시 upload라는 파일을 생성하고,  multer를 통해 저장위치와 파일도 추출했습니다. 

이후 POST /post/images 라우터에서 프론트의 key 값이 일치해야 파일을 가져오는데 

1. 현재 quill editor를 사용, image file을 올리면 사진이 첨부되지 않고 요청에 대한 result를 받아오지 못합니다. (saga)

그런데 SUCCESS 까지는 잘 넘어갑니다.


// saga post

function uploadImagesAPI(data) {
return axios.post(`/post/images`, data); // data: post.id
}

function* uploadImages(action) {
try {
const result = yield call(uploadImagesAPI, action.data);
console.log('result', result);
// yield delay(1000);
yield put({
type: UPLOAD_IMAGES_SUCCESS,
data: result.data,
});
} catch (err) {
yield put({
type: UPLOAD_IMAGES_FAILURE,
error: err.response.data,
});
}
}

 

2. quill editor 사용법과 많은 코드들을 참고하여 작성한 로직입니다.

//* quill text editor
const QuillNoSSRWrapper = dynamic(import('react-quill'), {
ssr: false,
loading: () => <p>Loading ...</p>,
});

const formats = [
'header',
'font',
'size',
'bold',
'italic',
'underline',
'strike',
'blockquote',
'list',
'bullet',
'indent',
'link',
'image',
'video',
];

//* AddPost
const AddPost = () => {
const dispatch = useDispatch();
const { me, addPostError, imagePaths } = useSelector((state) => state.user);
console.log('imagePaths', imagePaths);

const [title, onChangeTitle] = useInput('');
const [category, setCategory] = useState();
const [content, setContent] = useState('');

const quillRef = useRef();

//* quill text editor
const imageHandler = (e) => {
console.log('에디터의 이미지 버튼을 클릭하면 이 핸들러가 시작됩니다.'); // true
const input = document.createElement('input'); // 1. 이미지를 저장할 input type=file DOM을 만든다.
// 속성 써주기
input.setAttribute('type', 'file');
input.setAttribute('accept', 'image/*');
input.click(); // 에디터 이미지버튼을 클릭하면 이 input이 클릭된다. input이 클릭되면 파일 선택창이 나타난다.

input.addEventListener('change', async () => {
console.log('onChange');
const file = input.files[0];
const imageFormData = new FormData(); // multer에 맞는 형식으로 데이터 만들어준다.
[].forEach.call(file, (f) => {
imageFormData.append('image', f); // formData는 키-밸류 구조
});
dispatch({
type: UPLOAD_IMAGES_REQUEST,
data: imageFormData,
});
});
};

//* quill text editor
// useMemo를 사용한 이유는 modules가 렌더링마다 변하면 에디터에서 입력이 끊기는 버그가 발생
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 },
},
}),
[],
);
 
const onSubmit = useCallback(
(e) => {
e.preventDefault();
if (!title) {
return alert('제목을 입력하세요');
} else if (!category) {
return alert('카테고리를 설정하세요');
} else if (!content) {
return alert('게시글을 작성하세요');
}
const formData = new FormData();
imagePaths.forEach((p) => {
formData.append('image', p);
});
formData.append({ title: title, category: category, content: content });
// dispatch loadPostRequest
dispatch({
type: ADD_POST_REQUEST,
data: formData,
});
// error 없으면 community 목록으로 이동
if (!addPostError) {
Router.push('/community');
}
},
[title, category, content],
);
 
<QuillNoSSRWrapper
ref={quillRef}
modules={modules}
formats={formats}
theme="snow"
placeholder={`${me?.nickname}님의 글을 입력해주세요`}
value={content}
onChange={setContent}
/>
 
참고: https://github.com/ko7452/e-Library/tree/master/prepare
 

혹시 제가 quill editor를 잘못 사용하거나

이해를 못하는 듯 한데.. 조언 주실 수 있을까요?

답변 1

답변을 작성해보세요.

0

퀼에디터는 안 써봐서 모르겠습니다만 result가 안 오는데 success가 호출되는건 말이 안됩니다.

채널톡 아이콘