2 분 소요


Styled-Components를 사용하여 이미지 기본 설정과 스타일링을 구현해보자.


1. 기본 이미지 설정하기

사용자가 프로필 이미지가 없는 경우, 기본 이미지를 설정하여 보여줄 수 있다.

  1. 프로젝트의 assets/images 폴더에 기본 이미지를 추가하기
  2. 해당 이미지를 컴포넌트에서 사용할 수 있도록 import하기.
import defaultUser from "assets/images/defaultUser.png";



2. Styled-Components로 이미지 스타일링하기

StLetterCardAvatorFigure라는 styled-component를 정의하여 이미지 컨테이너를 스타일링한다.

  1. figure 태그를 Styled-Components로 감싸 이미지의 크기와 스타일을 지정하기
  2. overflow: hidden을 사용하여 이미지가 컨테이너를 넘치지 않게 하고, border-radius로 둥글게 만들기
import styled from "styled-components";
import defaultUser from "assets/images/defaultUser.png";

const LetterCard = () => (
  <StLetterCardAvatorFigure>
    <img src={user.avatar || defaultUser} alt="아바타 이미지" />
  </StLetterCardAvatorFigure>
);

const StLetterCardAvatorFigure = styled.figure`
  width: 50px;
  height: 50px;
  border-radius: 50%;
  overflow: hidden;

  & img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: 50%;
  }
`;



3. 프로필 변경 기능 구현하기

이제 사용자가 프로필 사진과 닉네임을 변경할 수 있는 기능을 구현해보자

이미지와 텍스트 데이터를 FormData로 서버에 전송하는 방식이며, 서버에 프로필 변경 요청을 보낸 후 응답을 받아 상태를 업데이트한다.


  • 프로필 수정 시 서버로 nickname과 avatar 이미지를 보내기 위해 FormData 객체를 사용한다.
  • 이미지 파일과 텍스트 데이터를 서버로 전송할 수 있도록 multipart/form-data 형식으로 요청한다.
//src/api/auth.js
export const editProfile = async (data) => {
  const formData = new FormData();
  formData.append("avatar", data.avatar);
  formData.append("nickname", data.nickname);

  return await authAxios.patch("/profile", formData, {
    headers: {
      "Content-Type": "multipart/form-data",
    },
  });
};
// src/pages/protected/Mypage.jsx
import { editProfile } from "api/auth";
import { useAuth } from "context/AuthContext";
import { useState, useEffect } from "react";
import styled from "styled-components";
import defaultUser from "assets/images/defaultUser.png";

const MyPage = () => {
  const { user, setUser } = useAuth();
  const [isEditMode, setIsEditMode] = useState(false);
  const [editNickname, setEditNickname] = useState(user.nickname || ""); // 편집할 닉네임 상태
  const [imgFile, setImgFile] = useState(null); // 선택한 이미지 파일
  const [previewUrl, setPreviewUrl] = useState(""); // 이미지 미리보기 URL

  // 편집 모드가 아닐 때 원래 닉네임과 이미지를 설정
  useEffect(() => {
    setEditNickname(user.nickname || "");
    setPreviewUrl(user.avatar ? user.avatar : defaultUser);
  }, [user]);

  // 파일 선택 시 호출되는 함수
  const handleFileChange = (e) => {
    const file = e.target.files[0];
    // if (imgFile.size > 1024 * 1024) {
    //   return alert('최대 1MB까지 업로드 가능합니다.');
    // }

    setImgFile(file); // 선택한 파일 저장

    //  미리보기 URL 생성(File -> Url 형식으로 변환)
    const imgUrl = URL.createObjectURL(file);
    setPreviewUrl(imgUrl);
  };

  // 프로필 변경 처리 함수
  const handleProfileChange = async () => {
    try {
      const response = await editProfile({
        nickname: editNickname,
        avatar: imgFile,
      });
      setUser(response.data);
      alert("변경 완료!");
      setIsEditMode(false);
    } catch (error) {
      console.error("프로필 변경 중 오류 발생:", error);
    }
  };

  return (
    <div>
      <h2>프로필 관리</h2>

      {isEditMode ? (
        <>
          <StMyPageFigure>
            <img src={previewUrl} alt="아바타 이미지" />
          </StMyPageFigure>
          <input type="file" onChange={handleFileChange} />
          <input
            value={editNickname}
            onChange={(e) => setEditNickname(e.target.value)}
            placeholder="변경할 닉네임"
          />
          <button onClick={handleProfileChange}>변경완료</button>
          <button onClick={() => setIsEditMode(false)}>취소</button>
        </>
      ) : (
        <>
          <StMyPageFigure>
            <img src={user.avatar || defaultUser} alt="아바타 이미지" />
          </StMyPageFigure>
          <div>{user.nickname}</div>
          <button onClick={() => setIsEditMode(true)}>
            닉네임 및 이미지 변경
          </button>
        </>
      )}
    </div>
  );
};

export default MyPage;

const StMyPageFigure = styled.figure`
  width: 50px;
  height: 50px;
  border-radius: 50%;
  overflow: hidden;

  & img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: 50%;
  }
`;


카테고리:

업데이트:

댓글남기기