selector 구성

저는 셀렉터를 너무 세분화해서 나누게 되면 오히려 유지보수 측면에서 고려해야할 점이 많아질 것 같아 셀렉터를 각 slice를 기준으로 나눴습니다. 맨 처음에 셀렉터를 잘게 쪼갤지, 슬라이스 단위로 쪼갤지 고민해 보았습니다.

  1. 잘게 쪼개는 경우, 선택한 값에 변경이 일어날때만 리렌더링이 되므로 성능적인 최적화를 이뤄낼 수 있지만, 이로 인해 코드가 늘어나고 가독성 및 유지보수성이 떨어지게 되는 단점이 있습니다.
  2. 슬라이스 단위로 쪼개는 경우, 해당 슬라이스의 값이 변경되면 그 안의 값들도 리렌더링이 됩니다. 이로인해 성능적인 이슈가 있을 수 있습니다. 하지만 코드가 간결하고 셀렉터의 유지보수성에서 이점이 있습니다.

기본적으로 사용하는 컴포넌트 단위로 쪼개는 것이 맞다고 생각했고, 처음부터 최적화를 고려하기 보다는 진행을 하면서 문제가 되는 부분에 최적화를 추가하는 방식으로 진행하고자 했습니다. 따라서 셀렉터를 "슬라이스" 단위로 구성하였습니다.

주문서 selector

export const selectDeliveryAddress = (state: RootState) => state.orderSheetReducer.deliveryAddress
export const selectOrderPayMethod = (state: RootState) => state.orderSheetReducer.orderPayMethod
export const selectOrderProduct = (state: RootState) => state.orderSheetReducer.orderProduct
export const selectPointsReward = (state: RootState) => state.orderSheetReducer.pointsReward
export const selectSubscriptionDate = (state: RootState) => state.orderSheetReducer.subscriptionDate

createSelector는 selector로부터 파생된 데이터를 구성하기 위해 사용했습니다. selectSubscriptionData는 '구독 신청하기' 버튼을 누르고 출력되는 데이터들을 구성합니다.

export const selectSubscriptionData = createSelector(
    [selectDeliveryAddress, selectOrderProduct, selectOrderPayMethod],
    (address, product, payMethod) => {
        const deliveryAddressInfo = {
            ...address,
        }
        const paymentInfo = {
            expectedPayAmount: product.totalOrderAmount,
            subscriptionPayMeansNo: String(payMethod.orderPayMethodNo),
            useAllCoupon: product.useAllCoupon,
        }

        return {deliveryAddressInfo, paymentInfo}
    },
)

selectStorageUIState는 원복할 데이터를 추적하기 위한 셀렉터입니다.

export const selectStorageUIState = createSelector(
    [selectDeliveryAddress, selectOrderProduct],
    (deliveryAddress, orderProduct) => ({
        useAllCoupon: orderProduct.useAllCoupon,
        useVirtualPhoneNumber: deliveryAddress.useVirtualPhoneNumber,
        reuseMemo: deliveryAddress.reuseMemo,
        selectedMemo: deliveryAddress.selectedMemo,
    }),
)

결제수단 변경 selector

결제수단 변경 셀렉터도 슬라이스를 기준으로 나누었습니다.

export const selectPaymoneyAndPoint = (state: RootState) => state.paymentMethodReducer.paymoneyAndPoint
export const selectPaymentMethod = (state: RootState) => state.paymentMethodReducer.paymentMethod
export const selectCashReceipt = (state: RootState) => state.paymentMethodReducer.cashReceipt

selectRegisterData는 결제수단 등록 버튼을 클릭하여 데이터를 구성하기 위한 셀렉터입니다.

export const selectRegisterData = createSelector(
    [selectPaymoneyAndPoint, selectPaymentMethod, selectCashReceipt],
    (paymoneyAndPoint, paymentMethod, cashReceiptResult) => {
        const {usePointAll} = paymoneyAndPoint
        const {cashReceipt, useCashReceipt: cashReceiptApply} = cashReceiptResult
        const {firstPayment, secondPayment} = paymentMethod

        const firstPayMethod = formatRegisterPaymentMethod(firstPayment)
        const secondPayMethod = formatRegisterPaymentMethod(secondPayment)

        if (firstPayMethod && !secondPayment) {
            return {
                cashReceipt,
                firstPayMethod,
                usePointAll,
                cashReceiptApply,
                entry: 'SUBSCRIPTION',
            }
        }

        if (firstPayMethod) {
            return {
                cashReceipt,
                firstPayMethod,
                secondPayMethod,
                usePointAll,
                cashReceiptApply,
                entry: 'SUBSCRIPTION',
            }
        }
    },
)

비동기 상태 selector

export const selectAsyncStatus = (state: RootState) => state.asyncStatus