프로필 이미지 변경

개발공부·2023년 1월 10일
0

* 결과

1) 기본 이미지 -> 이미지 변경

2) 이미지 변경 후 다른 페이지 이동

* 기본 이미지 출처
https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_1280.png

* 고려할 점

▶ 정말 어려웠다;
▶ 처음에는 이미지를 올리면 올리려는 이미지가 보이고 최종 이미지를 업로드하는 것이었는데
이 과정에서 문제가 계속 있었다
(결론) 이미지를 올리면 user 정보(me)에 이미지가 저장되고 화면에 로딩되는 것

useEffect(() => {
dispatch(loadMyInfoRequest());
}, [imagePaths]);
//imagePaths 값이 변경될 때마다(프로필 이미지 변경될 때 마다 load됨)

* 코드

[pages/profile.js]

import React, { useEffect } from "react";

import Profile from "../components/Profile";
import { loadPostsRequest } from "../redux/feature/postSlice";
import { loadMyInfoRequest } from "../redux/feature/userSlice";
import { loadWordsRequest } from "../redux/feature/wordSlice";

const profile = () => {
  const dispatch = useDispatch();
  const { me } = useSelector((state) => state.user);
  const { mainPosts } = useSelector((state) => state.post);
  const { wordLists } = useSelector((state) => state.word);

  const id = useSelector((state) => state.user.me?.id);
  const { imagePaths } = useSelector((state) => state.user);
  const postResult = mainPosts.filter((post) => post.UserId === id);
  const wordResult = wordLists.filter((word) => word.UserId === id);

  useEffect(() => {
    dispatch(loadPostsRequest());
    dispatch(loadWordsRequest());
  }, []);

  useEffect(() => {
    dispatch(loadMyInfoRequest());
  }, [imagePaths]); //이 부분이 핵심(이미지가 변경될 때 load 다시 실행)
  
  return (
    <>
      <NavbarForm me={me}>
        {me ? (
          <Profile me={me} postResult={postResult} wordResult={wordResult} />
        ) : (
          <LoginForm />
        )}
      </NavbarForm>
    </>
  );
};

export default profile;

[components/Profile]

const Profile = ({ me, postResult, wordResult }) => {
  const imageInput = useRef();

  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(uploadProfileImageRequest(imageFormData));
  }, []);
  
  return (
  					<div className="flex">
                          <form encType="multipart/form-data">
                            <input
                              type="file"
                              name="image"
                              multiple
                              hidden
                              ref={imageInput}
                              onChange={onChangeImages}
                            />
                            <div className="flex">
                              <button
                                type="button"
                                className="bg-gray-100 rounded-full w-28 h-5 relative left-32 bottom-10 cursor-pointer "
                                onClick={onClickImageUpload}
                              >
                                <p className="font-bold">프로필 변경</p>
                              </button>
                            </div>
                          </form>
                          
                           {me.profileImg === "" ? (
                          <img
                            alt="profile-img"
                            src="https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_1280.png" //초기값
                            className="rounded-full h-40 w-40"
                          />
                        ) : (
                          <img
                            className="rounded-full h-40 w-40"
                            src={`http://localhost:3005/profile/${me.profileImg}`} //변경된 이미지
                            alt={me.profileImg}
                          />
                        )}

  
  )
}
export default Profile

[userSaga.js]

function uploadProfileImageAPI(data) {
  return axios.post("/user/image", data);
}

function* uploadProfileImage(action) {
  try {
    const data = action.payload;
    const result = yield call(uploadProfileImageAPI, data);
    yield put(uploadProfileImageSuccess(result.data));
  } catch (error) {
    yield put(uploadProfileImageFailure(error));
    console.log(error);
  }
}

[userSlice.js] - redux-toolkit

    uploadProfileImageSuccess: (state, action) => {
      const data = action.payload;
      state.imagePaths = data;
      state.uploadProfileImageLoading = false;
      state.uploadProfileImageComplete = true;
    },

[backend routes/user]

▶ model에 user 정보에 이미지 넣을 곳 필요(본인은 string타입, profileImg로 지정)

const fs = require("fs");
const path = require("path");

const { User } = require("../models");
const { isLoggedIn, isNotLoggedIn } = require("./middlewares");

const router = express.Router();

try {
  fs.accessSync("uploads/profile");
} catch (error) {
  console.log("uploads/profile 폴더가 없으므로 새로 생성합니다.");
  fs.mkdirSync("uploads/profile");
}

//프로필 이미지
const upload = multer({
  storage: multer.diskStorage({
    destination(req, file, done) {
      done(null, "uploads/profile");
    },
    filename(req, file, done) {
      //파일이미지.png
      const ext = path.extname(file.originalname); //확장자 추출(.png)
      const basename = path.basename(file.originalname, ext); //파일이미지
      done(null, basename + "_" + new Date().getTime() + ext); //파일이미지1234849.png
    },
  }),
  limits: { fileSize: 20 * 1024 * 1024 }, // 20MB
});

router.post(
  "/image",
  isLoggedIn,
  upload.single("image"), //하나의 이미지만 필요
  async (req, res, next) => {
    await User.update(
      { profileImg: req.file.filename },
      { where: { id: req.user.id } }
    );
    res.json(req.file);
  }
);
profile
개발 블로그, 티스토리(https://ba-gotocode131.tistory.com/)로 갈아탐

0개의 댓글