팀 프로젝트 post 페이지 제작기#1

SeanKim·2023년 12월 15일

프로젝트를 진행하면서, 임무 분담을 하던 중 내 역할은 롤링페이지를 생성하는 페이지를 제작해야 했다.

요구사항

  1. 토글 버튼의 선택에 따라 배경화면을 컬러, 이미지 선택지로 보여준다.
  2. 받는 사람의 이름, 배경화면(이미지면 주소, 또는 컬러)를 받고, 생성하기 버튼을 누르면 해당 데이터를 POST한다. 즉, 롤링페이지를 생성한다.
  3. 생성에 성공하면 /post/{id} 페이지로 이동한다.
  4. 이름을 입력하지 않으면 버튼은 disabled 상태가 된다.

제작 중 문제 발생


기존 팀원들이 만든 컴포넌트를 가져오다 보니, 요구하는 디자인에 맞지 않는 문제가 있었다.
또한 옵션 선택 버튼은 선택한 요소만 체크 표시가 되어있어야 하는데 전부 체크가 되어있는, 미완성의 상태였다.

해결 과정

우선 페이지가 어떻게 동작할 지 구조를 설계했다.

  1. 페이지가 로딩되면, 이미지 데이터를 받아오도록 한다.
  2. 입력창에 입력한 이름은 POST 요청할 데이터에 저장된다.
  3. 토글 버튼을 선택하면, 분기에 따라 컬러 배경 또는 이미지 배경을 보여준다.
  4. 배경을 선택했을 때, 선택한 값에 따라 체크 표시를 보여주도록 했다.
  const [postData, setPostData] = useState({
    team: '2-12',
    name: '',
    backgroundColor: 'beige',
    backgroundImageURL: null,
  });

state를 활용하여 초기 post 데이터를 설정했다.

input 스타일 수정

const InputStyle = styled.input`
  display: flex;
  width: 100%;

우선 input width를 수정하였다.

input에 props 전달

        <Input
          placeholder="받는 사람 이름을 입력해주세요."
          onChange={setPostData}
          postData={postData}
        />

input 컴포넌트에는, placeholder를 지정하고, 변할 때 postData를 바꾸도록 props로 전달해주었다.

// Input.jsx
  const handleChange = (e) => {
    onChange({ ...postData, name: e.target.value });
  };

로딩시 이미지 가져오기

// CreateRecipientPage
  const handleLoad = async () => {
    let result;
    try {
      result = await getBackgroundImages();
      setBackgroundImages([...result]);
    } catch (error) {
      return;
    }
  };

  useEffect(() => {
    handleLoad();
  }, []);

페이지 최초 로딩 시 이미지 데이터를 가져오도록 했다. 이미지에 대한 내용은 backgroundImages라는 state에 저장하도록 했다.

토글 버튼 선택지

<ToggleBtn onClick={setIsActive} isActive={isActive} />

// ToggleBtn.jsx
  const handleClick = () => {
    onClick(!isActive);
  };

토글 버튼을 클릭할 때 마다 isActive를 참, 거짓으로 설정 했다.

배경 선택하는 기능 구현

// CreateRecipientsPage
<Selector
          isImage={isActive}
          onClick={setPostData}
          postData={postData}
          backgroundImages={backgroundImages}
        />

페이지 컴포넌트에서는 isActive에 따른 이미지 배경 분기를 props로 전달했다.
클릭 이벤트 onClick에 사용하기 위해 postData를 수정하도록 props로 주었고, 로딩될 때 받아온 이미지 데이터를 props로 전달해줬다.

const COLOR = [
  { value: 'beige', color: 'var(--orange-200, #FFE2AD)' },
  { value: 'purple', color: 'var(--purple-200, #ECD9FF)' },
  { value: 'blue', color: 'var(--blue-200, #B1E4FF)' },
  { value: 'green', color: 'var(--green-200, #d0f5c3)' },
];

const OptionItem = styled.button`
  background: ${({ $background }) => ($background ? $background : 'red')};

`;

const CheckIcon = styled.img`
  display: flex;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  padding: 1rem;
  align-items: flex-start;
  border-radius: 10rem;
  background: var(--gray-500, #555);
`;

export default function Option({
  isImage,
  onClick,
  postData,
  backgroundImages,
}) {
  const [selectedIndex, setSelectedIndex] = useState(0);
  const BACKGROUND = backgroundImages;
  const data = isImage ? BACKGROUND : COLOR;


  return (
    <OptionContainer>
      {data.map((item, index) => {
        return (
          <OptionItem
            key={index}
            $background={isImage ? `url(${item})` : item.color}
            id={index}
            type="button"
            onClick={handleClick}>
            {selectedIndex === index && (
              <CheckIcon src={checkImg} alt="체크됨" />
            )}
          </OptionItem>
        );
      })}
    </OptionContainer>
  );
}

jsx

미완성인 부분이 많아 사실상 스타일을 제외하고 처음부터 제작해야 했다.
props로 전달받은 backgroundImages를 저장하고, isImage 분기에 따라 map에 사용할 데이터를 바꿔줬다.

map에서는 데이터를 반복하여 선택 박스를 생성했고, OptionItem에 스타일 분기를 위한 $background 및 id값, onClick 이벤트, 체크에 따른 CheckIcon을 반환하도록 했다.

handleClick

  const handleClick = (e) => {
    const id = Number(e.target.id);
    if (isImage) {
      onClick({ ...postData, backgroundImageURL: BACKGROUND[id] });
      setSelectedIndex(Number(id));
    } else {
      onClick({
        ...postData,
        backgroundColor: COLOR[id].value,
        backgroundImageURL: null,
      });
      setSelectedIndex(Number(id));
    }
  };

OptionItem의 id를 사용해 데이터를 바꿔주도록 했다.
destructuring 문법을 활용해 페이지 컴포넌트의 postData를 수정하도록 했다.
이미지 분기에 따라 backgroundImageURL을 추가하거나, backgroundColor를 바꿔주도록 했다.

선택한 인덱스를 id값으로 반영하도록 해서 체크 표시를 할 수 있도록 state로 지정해줬다.

useEffect

  useEffect(() => {
    setSelectedIndex(0);
    if (isImage) {
      onClick({ ...postData, backgroundImageURL: BACKGROUND[0] });
    } else {
      onClick({
        ...postData,
        backgroundColor: COLOR[0].value,
        backgroundImageURL: null,
      });
    }
  }, [isImage]);

토글버튼에 선택에 따른 isImage값이 바뀌면, 즉 이미지에서 컬러 또는 컬러에서 이미지로 수정될 때 처음 값을 지정해주기 위해 선택 id를 0으로 초기화 시켜줬다.

제출 기능 구현

// CreateRecipientPage.jsx
  const handleSubmit = async (e) => {
    e.preventDefault();
    let result;
    try {
      result = await postRecipients(postData);
    } catch (error) {
      return;
    }
    console.log(result);
  };

다시 페이지로 돌아와서 제출버튼 클릭 시 저장된 포스트 할 데이터를 POST 요청 시켜줬다.
이후 콘솔로 출력해서 잘 보내졌는지 확인할 수 있도록 하였다.

현재까지의 결과

제출 버튼 클릭 시


post 요청이 성공하여 제대로 결과값을 받아왔다.

앞으로 무엇을 더 해야할까

  1. 생성하기 버튼 클릭 후 생성에 성공하면 /post/{id} 페이지로 이동한다.
  2. 이름을 입력하지 않으면 버튼은 disabled 상태가 된다.
  3. 시안에서 제시된 페이지 디자인에 맞게 요소들의 간격을 배치 해야한다.
profile
프론트엔드 공부 중

0개의 댓글