[CryptoMeter] InputBoard 컴포넌트 제작

0

CryptoMeter

목록 보기
6/6
post-thumbnail

InputBoard 컴포넌트를 본격적으로 만들어 보았다. 작업은 다음과 같은 순서로 진행하였다.
1. 컴포넌트 스켈레톤 제작
2. 반응형 디자인 적용하기
3. 기본 기능 붙이기

컴포넌트 스켈레톤 제작

박스 구성하기

디자인 시안은 다음과 같다.

필요한 엘리먼트를 나열해보면 헤딩, 날짜 input, 금액 input, 금액 증가 버튼, 코인 선택 input과 submit버튼이 있다.

inputs

우선, 먼저 만들어 둔 코인 선택 드롭다운 컴포넌트와 디자인이 동일한 것을 활용하여, 모든 인풋들이 들어가는 자리에 드롭다운 컴포넌트를 넣어 시안에 맞게 배치시켰다.

// InputBoardPresenter.jsx
    <S.BoardWrapper
      col
      ast
      sb
      bg={colors.gray9}
      br={24}
      pd="60px 40px 70px 40px"
    >
      <S.Form>
        <S.BoardBody col ast full sb g={55}>
          <SHeading2>
            <SText mgb={7}> 내가 만약</SText>
            <S.Br first />
            <SText white mgb={7}>
              {historyDate || "0000년 00월 00일"}
            </SText><S.Br second />
            <SText white mgb={7}>
              {selectMoney || "0"}
            </SText>
            원으로&nbsp;
            <S.Br third />
            <SText white>{selectedCoinId || "Bitcoin"}</SText>을 샀다면,
          </SHeading2>
          <S.InputArea col g={25} full>
            <Dropdown options={dropdownCoinOptionList} />
            <SDiv col act g={12}>
              <Dropdown options={dropdownCoinOptionList} />
              <S.IncreaseButtonListWrapper row sb full>
                {INCREASE_MONEY_UNITS.map((unit) => (
                  <IncreaseMoneyButton key={unit} money={unit} />
                ))}
              </S.IncreaseButtonListWrapper>
            </SDiv>
            <Dropdown options={dropdownCoinOptionList} />
          </S.InputArea>
        </S.BoardBody>
        <S.SubmitArea ct>
          <S.SubmitButton
            full
            h={64}
            br={35}
            white
            type="submit"
            onClick={handleClickSubmit}
          >
            <S.SubmitButtonText s1 black>
              오늘 얼마가 되었을까?
            </S.SubmitButtonText>
          </S.SubmitButton>
        </S.SubmitArea>
      </S.Form>
    </S.BoardWrapper>

비주얼은 아래와 같다.

우선적으로 배치가 잘 된 것을 알 수 있다.

반응형 레이아웃 적용하기

이제 반응형 디자인을 적용시켜 보자.
다음은 반응형 디자인 시안이다.

모바일에서는 보드의 헤딩만 남고, 입력 폼 전체가 필터 버튼을 누르면 바텀시트처럼 올라오는 구조임을 알 수 있다.
인풋과 서브밋 버튼을 form태그로 묶어 관리하고 있어서, 이 form태그를 다음과 같이 기본적으로 모바일에서는 display: none을 적용시켜 숨겨준다.

  form {
    width: 100%;
    display: flex;
    flex-direction: column;
    gap: 189px;

    @media only screen and (max-width: 768px) {
      display: ${(props) => (props.isOpen ? "flex" : "none")};
      position: fixed;
      bottom: ${(props) => (props.isOpen ? "-556px" : "0")};
      left: 0;
      z-index: 10;
   }

또한 styled component를 사용하고 있으므로 props로 열린 상태에 따라 display속성을 flex로 바꿔준다. 위의 isOpen props는 모바일 인풋보드의 필터 버튼을 누르면 true로 바뀌게 되어있다.
결과는 다음과 같다.

기본 기능 붙이기

위에 dropdown으로 모양을 잡았던 부분들을 전부 실제 인풋 타입에 맞는 input태그들로 교체적용 시켜줘야 한다. 물론 디자인은 드롭다운의 디자인을 따라갔다.
먼저, 날짜를 선택하는 부분은 <input type="date"../>, 금액은 <input type="number" ../>로 교체해준다. 또한 금액 input의 경우 드롭다운 핸들 대신 화폐 단위 라벨이 있다. 이것 또한 반영해준다.

// InputBoardPresenter.jsx
 <S.InputArea col g={25} full className="GI">
  <DateInput isOpen={false} selectedDate="2022년 10월 12일" />
  <SDiv col act g={12}>
    <MoneyInput selectedMoney={"15000"} isOpen={false} />
    <S.IncreaseButtonListWrapper row sb full>
      {INCREASE_MONEY_UNITS.map((unit) => (
        <IncreaseMoneyButton
          key={unit}
          money={unit}
          onClick={() => {
            handleClickIncreaseMoney(unit);
          }}
          />
      ))}
    </S.IncreaseButtonListWrapper>
  </SDiv>

input의 value연동시키기

다음과 같이 input이 발생할 때마다 사용자의 입력값을 state에 반영시켜 준다.
MoneyInput (금액 입력창)을 예로 들면, 부모 컴포넌트는 inputMoney라는 state를 가지고 있다. 그리고 이 state를 바꿔주는 함수인 setInputMoney를 MoneyInput컴포넌트에 onChange라는 이름의 props로 넘겨주고, 다음과 같이 input태그의 onChange속성에 넣어준다.

const MoneyInput = ({..., onChange, ...}) => {
  ...
  return (
    <S.InputWrapper isOpen={isOpen}>
      <SDiv row sb>
        <S.Input
          name="money"
          type="number"
          ... 
          onChange={(e) => {
            onChange(Number(e.target.value));
          }}
          ...
        />
        ...
  );
};

이런식으로 사용자의 입력값과 내부 state를 연동시켜주는 것을 controlled input이라고 한다. 만약 controll되고 있지 않은 input이 있다면 리액트에서 다음과 같은 경고를 콘솔에 출력하기도 한다.

위와 같은 방법으로 DateInput과 CoinDropdown도 기본 기능을 붙여준다.

이제 남은것은 submit기능이다. 다만 이 기능은 api호출을 동반하고, 전역 상태를 구독하여 input과 전역 상태값들을 싱크해주는 작업이 필요하여, zustand 스토어를 만들고 컴포넌트에서 구독하게 하는 작업 관련 포스팅 때 다루어 보겠다.

0개의 댓글