작성
·
328
0
안녕하세요. 강사님! 강의를 들으며 똑같이 작성했고 혹시 모를 오타가 있는지도 확인하면서 강사님 깃허브도 참조해보았는데 원인을 찾지 못하겠어서 문의드립니다. ㅠ ㅠ
이미지 업로드를 하면 아래와 같이 오류가 뜨고 redux dev tools 로 확인해 보았을 때
UPLOAD_IMAGES_REQUEST 만 처리되고 SUCCESS 로 넘어가지가 않아요.
리퀘스트 되어 있는 데이터를 보면 빈 값인 것을 보니 데이터가 넘어가지 않는 것 같은데 도무지 원인을 모르겠습니다. 업로드를 하면 에러가 나면서 서버연결도 끊깁니다. ㅜㅜ
제 코드에 뭐가 문제가 있는 건가요..?ㅠㅠ
확인 후 문제를 알려주시면 너무 감사할 것 같습니다..ㅠㅠㅠ
[redux]
import produce from "immer";
export const initialState = {
mainPosts: [],
// 이미지 업로드할 때 이미지의 경로들이 저장됨
imagePaths: [],
uploadImagesLoading: false,
uploadImagesDone: false,
uploadImagesError: null,
}
export const UPLOAD_IMAGES_REQUEST = "UPLOAD_IMAGES_REQUEST";
export const UPLOAD_IMAGES_SUCCESS = "UPLOAD_IMAGES_SUCCESS";
export const UPLOAD_IMAGES_FAILURE = "UPLOAD_IMAGES_FAILURE";
const reducer = (state = initialState, action) => {
return produce(state, (draft) => {
switch (action.type) {
case UPLOAD_IMAGES_REQUEST:
draft.uploadImagesLoading = true;
draft.uploadImagesDone = false;
draft.uploadImagesError = null;
break;
case UPLOAD_IMAGES_SUCCESS:
draft.imagePaths = action.data;
draft.uploadImagesLoading = false;
draft.uploadImagesDone = true;
break;
case UPLOAD_IMAGES_FAILURE:
draft.uploadImagesLoading = false;
draft.uploadImagesError = action.error;
break;
default:
break;
}
});
};
export default reducer;
[saga]
import axios from "axios";
import {
all,
fork,
put,
takeLatest,
throttle,
call,
} from "redux-saga/effects";
import {
UPLOAD_IMAGES_FAILURE,
UPLOAD_IMAGES_REQUEST,
UPLOAD_IMAGES_SUCCESS,
} from "../reducers/post";
function uploadImagesAPI(data) {
return axios.post("/post/images", data);
}
function* uploadImages(action) {
try {
const result = yield call(uploadImagesAPI, action.data);
yield put({
type: UPLOAD_IMAGES_SUCCESS,
data: result.data,
});
} catch (err) {
console.error(err);
yield put({
type: UPLOAD_IMAGES_FAILURE,
error: err.response.data,
});
}
}
function* watchUploadImages() {
yield takeLatest(UPLOAD_IMAGES_REQUEST, uploadImages);
}
export default function* postSaga() {
yield all([
fork(watchUploadImages),
]);
}
[components]
import React, { useCallback, useEffect, useRef } from "react";
import { useSelector, useDispatch } from "react-redux";
import { Form, Input, Button } from "antd";
import {
UPLOAD_IMAGES_REQUEST,
REMOVE_IMAGE,
ADD_POST_REQUEST,
} from "../reducers/post";
import useInput from "../hooks/useInput";
const PostForm = () => {
const dispatch = useDispatch();
const { imagePaths, addPostDone } = useSelector((state) => state.post);
const [text, onChangeText, setText] = useInput("");
const imageInput = useRef();
useEffect(() => {
if (addPostDone) {
setText("");
}
}, [addPostDone]);
const onSubmit = useCallback(() => {
if (!text || !text.trim()) {
return alert("게시글을 작성하세요.");
}
const formData = new FormData();
imagePaths.forEach((p) => {
formData.append("image", p);
});
formData.append("content", text);
return dispatch({
type: ADD_POST_REQUEST,
data: formData,
});
}, [text, imagePaths]);
const onClickImageUpload = useCallback(() => {
imageInput.current.click();
}, [imageInput.current]);
const onChangeImages = useCallback((e) => {
console.log("images", e.target.files);
const imageFormData = new FormData();
[].forEach.call(e.target.files, (f) => {
imageFormData.append("image", f);
});
dispatch({
type: UPLOAD_IMAGES_REQUEST,
data: imageFormData,
});
}, []);
const onRemoveImage = useCallback(
(index) => () => {
dispatch({
type: REMOVE_IMAGE,
data: index,
});
},
[]
);
return (
<Form
style={{ margin: "10px 0 20px" }}
encType="multipart/form-data"
onFinish={onSubmit}
>
<Input.TextArea
value={text}
onChange={onChangeText}
maxLength={140}
placeholder="어떤 신기한 일이 있었나요?"
/>
<div>
<input
type="file"
name="image"
multiple
hidden
ref={imageInput}
onChange={onChangeImages}
/>
<Button onClick={onClickImageUpload}>이미지 업로드</Button>
<Button type="primary" style={{ float: "right" }} htmlType="submit">
짹짹
</Button>
</div>
<div>
{imagePaths?.map((v, i) => (
<div key={v} style={{ display: "inline-block" }}>
<img
src={`http://localhost:3065/${v}`}
alt={v}
style={{ width: "200px" }}
/>
<div>
<Button onClick={onRemoveImage(i)}>제거</Button>
</div>
</div>
))}
</div>
</Form>
);
};
export default PostForm;
[back - routes/post.js]
const express = require("express");
const multer = require("multer");
const path = require("path");
const fs = require("fs");
const { Post, Image, Comment, User } = require("../models");
const { isLoggedIn } = require("./middlewares");
const router = express.Router();
try {
fs.accessSync("uploads");
} catch (error) {
console.log("uploads 폴더가 없으므로 생성합니다.");
fs.mkdirSync("uploads");
}
const upload = multer({
storage: multer.diskStorage({
destination(req, file, done) {
done(null, "uploads");
},
filename(req, file, done) {
// amanda.png
const ext = path.extname(file.originalname); // 확장자 추출(.png)
const basename = path.basename(file.originalname, ext); // amanda
done(null, basename + "_" + new Data().getTiem() + ext); // amanda15653484.png
},
}),
limits: { fileSize: 20 * 1024 * 1024 }, // 20MB
});
router.post(
"/images",
isLoggedIn,
upload.array("image"), // single , array , none
async (req, res, next) => {
// POST /post/images
console.log(req.files);
res.json(req.files.map((v) => v.filename));
}
);
router.post("/", isLoggedIn, upload.none(), async (req, res) => {
// POST /post
try {
const post = await Post.create({
content: req.body.content,
UserId: req.user.id,
});
if (req.body.image) {
if (Array.isArray(req.body.image)) {
// 이미지를 여러 개 올리면 image: [제로초.png, 부기초.png]
const images = await Promise.all(
req.body.image.map((image) => Image.create({ src: image }))
);
await post.addImages(images);
} else {
// 이미지를 하나만 올리면 image: 제로초.png
const image = await Image.create({ src: req.body.image });
await post.addImages(image);
}
}
const fullPost = await Post.findOne({
where: { id: post.id },
include: [
{
model: Image,
},
{
model: Comment,
include: [
{
model: User, // 댓글 작성자
attributes: ["id", "nickname"],
},
],
},
{
model: User, // 게시글 작성자
attributes: ["id", "nickname"],
},
{
model: User, // 좋아요 누른 사람
as: "Likers",
attributes: ["id"],
},
],
});
res.status(201).json(fullPost);
} catch (error) {
console.error(error);
next(error);
}
});
module.exports = router;
백엔드 서버를 키고 업로드 시키니 앱크러쉬가 나서 코드 다시 확인해보고 오류 잡았어요 :) 감사합니다ㅣ.