develop

날짜 기능이 있는 게시판 만들기 with datepicker (5) - 이벤트 수정시

crab. 2023. 2. 28. 07:20
  • 이벤트 수정시 쿠폰의 경우는 등록보다 훨씬 복잡하다.
    • 저장된 쿠폰 읽기
    • 저장된 쿠폰 수정하기
    • 새로운 쿠폰 저장하기
    • 저장된 새로운 쿠폰 수정하기
    • 쿠폰 삭제하기를 고려해야한다.
  • 그리고 각 경우마다 date의 형태가 다 다르다.
  • 거기다 수정과 읽기를 오갈때마다 date의 형식을 바꿔주는데 이때 비동기와 연관되어 비동기 통신, 형식 바꾸기, 바로 렌더링하기의 순서를 맞춰주는것이 나에게는 꽤나 힘든과정이었다.
    • 전에 썼던것을 다시 인용해보면
    • 이 부분이 어려웠던 이유는 날짜의 형식이 tz, date, 문자열(YYYY-MM-DD HH:mm)이 계속해서 바뀌었고 이 바뀐 데이터를 바로 유저에게 렌더링해서 보여줘야 했는데 이 부분이 useEffect와 useState의 깊숙한 부분을 건드리며 각각의 순간들(저장된 쿠폰 읽기, 저장된 쿠폰 수정하기, 새로운 쿠폰 저장하기, 새로운 쿠폰 수정하기)마다 서버와 api비동기 통신을 해서 데이터를 렌더링하기에 비동기 통신에 대한 넓은 이해와 적용이 필요했기 때문이다.

쿠폰 읽기

  • 나의 경우는 서버로 특정 이벤트의 id를 보내면 그 이벤트의 쿠폰을 배열로 보내주는 api가 있었다.
  • 따라서 이미 작성된 이벤트에서 수정하기를 클릭하면 그때 store의 coupon에 해당 배열을 넣어주면 된다.
useEffect(() => {
    if (!checkedUpdate) dispatch(__getEventCoupon(id));
  }, [dispatch, id]);
///checkedUpdate의 쓰임새는 좀 있다 작성한다.

const { coupon, checkedUpdate } = useSelector(state => state.event);
  • 이렇게 서버로 부터 읽어온 쿠폰 목록은
<Fragment>
      {currentItems &&
        currentItems.map((v, idx) => (
          <CouponCard
            event={v}
            idx={idx}
            updateState={updateState}
            deleteState={deleteState}
          />
        ))}
    </Fragment>
  • 페이지네이션에서 map을 통해 각 쿠폰목록 컴포넌트로 props 전달한다.
  • 이후는 CouponCard들이 하나씩 쿠폰목록을 렌더링한다.
  • 여기서 주의할 점은 앞선 포스팅에서 얘기 했듯이 서버의 DB에는 GMT로 등록되므로 9시간을 빼주어야 한다는 점이다.
				<Items className="col">
          {event.startExpDate === "" ? (
            <div>-</div>
          ) : (
            <div>
              {moment(Date.parse(event.startExpDate))
                .add(-9, "h")
                .format("YYYY-MM-DD")}
              &nbsp;
              {moment(Date.parse(event.startExpDate))
                .add(-9, "h")
                .format("hh:mm A")}
              <p>
                -&nbsp;
                {moment(Date.parse(event.endExpDate))
                  .add(-9, "h")
                  .format("YYYY-MM-DD")}
                &nbsp;
                {moment(Date.parse(event.endExpDate))
                  .add(-9, "h")
                  .format("hh:mm A")}
              </p>
            </div>
          )}
        </Items>

새로운 쿠폰 저장하기

  • 우선은 코드의 흐름을 위해 이벤트 수정시 새로운 쿠폰을 등록할 때 어떻게 했는지 봐보자
  • 이벤트 수정시 새로운 쿠폰을 저장할때는 기존의 이벤트 등록시의 로직과 크게 다르지는 않다.
  • 다만, 저장하는 함수를 호출할때가 살짝 다르다.
  • 기존의 이벤트 등록시에는 쿠폰목록을 보여줄 때 그 데이터가 온전히 전부 프론트내에서의 데이터였다.
  • 따라서 굳이 가공할 필요없이 YYYY-MM-DD HH:mm 형태로 보내주기만 하면 됐다.
  • 하지만 수정의 경우는 서버로부터 받은 쿠폰들이 존재하기 때문에 그 기존 쿠폰들의 형식을 프론트로 바꾸거나 아니면 저장할때 형식을 서버와 맞게 바꾸어야 한다.
  • 결국 핵심은
    • 프론트는 date객체
    • 서버는 tz
    • 보낼때는 YYYY-MM-DD HH:mm 라는 것이다.
  • 나는 쿠폰 목록을 읽을 때의 편의를 위해 서버쪽 형식인 tz로 데이터를 다루기로 했다.
  • 따라서 쿠폰을 저장할때는 쿠폰읽을때의 형식을(+9, tz) 맞추기 위해
				_postCoupon({
          name: couponName,
          primaryCondition: condition,
          secondaryCondition: condition,
          conditionName: issuanceCondition,
          targetProduct: item,
          minPrice: minPrice,
          amount: amount,
          discountType: discountType,
          discountValue: discountValue,
          discountPercentageMaxPrice: discountPercentageMaxPrice,
          startExpDate: moment(open)
            .add(9, "h")
            .tz("America/Toronto")
            .utc()
            .format(),
          endExpDate: moment(close)
            .add(9, "h")
            .tz("America/Toronto")
            .utc()
            .format(),
        }),
  • 로 맞춰준다.

저장된 쿠폰 & 새로 저장한 쿠폰 수정하기

  • 위에서 date 형식을 tz로 맞췄기 때문에 기존의 쿠폰이나 새로 저장한 쿠폰이나 같은 방식으로 수정하면된다.
  • 수정이기 때문에 기존의 날짜date가 있다. (tz형식)
  • 이는 전에 이벤트 등록시 쿠폰수정할때의 방식을 이용해 9시간을 빼주고 date형식으로 바꿔준다.
	const [startDate, setStartDate] = useState(
    new Date(new Date(couponData.startExpDate).getTime() - 9 * 60 * 60 * 1000),
  );
  const [endDate, setEndDate] = useState(
    new Date(new Date(couponData.endExpDate).getTime() - 9 * 60 * 60 * 1000),
  );
  const [startTime, setStartTime] = useState(
    new Date(new Date(couponData.startExpDate).getTime() - 9 * 60 * 60 * 1000),
  );
  const [endTime, setEndTime] = useState(
    new Date(new Date(couponData.endExpDate).getTime() - 9 * 60 * 60 * 1000),
  );
  • 이렇게 함으로써 datepicker에는 기존의 날짜가 기본값으로 나오게된다.
  • 또한 수정을 마칠때는 쿠폰 저장할때와 마찬가지로
			dispatch(
        _updateCoupon({
          idx: couponId,
          coupon: {
            name: couponName,
            primaryCondition: primaryCondition,
            secondaryCondition: secondaryCondition,
            discountPercentageMaxPrice: discountPercentageMaxPrice,
            targetProduct: targetProduct,
            minPrice: minPrice,
            amount: amount,
            discountType: discountType,
            discountValue: discountValue,
            startExpDate: moment(open)
              .add(9, "h")
              .tz("America/Toronto")
              .utc()
              .format(),
            endExpDate: moment(close)
              .add(9, "h")
              .tz("America/Toronto")
              .utc()
              .format(),
          },
        }),
      );
  • 로 하면 된다.

문제는?

  • 문제는 서버에 보내는 형식이 YYYY-MM-DD HH:mm 여야 한다는 점이다.
  • 이 문제를 해결하기 위해 고민을 해본 결과 한가지 방법이 떠오른게
  • 쿠폰설정 모달에서 유저는 반드시 닫기 버튼을 누른다는 점이었다.
  • 따라서 나의 경우
		_updateCouponDate: (state, action) => {
      for (let i = 0; i < state.coupon.length; i++) {

        state.coupon[i].startExpDate = moment(
          Date.parse(state.coupon[i].startExpDate),
        )
          .add(-9, "h")
          .format("YYYY-MM-DD HH:mm:ss");

        state.coupon[i].endExpDate = moment(
          Date.parse(state.coupon[i].endExpDate),
        )
          .add(-9, "h")
          .format("YYYY-MM-DD HH:mm:ss");
      }
    },