본문 바로가기

Study/React

[React Native] 다른 페이지로 값 전달하기

앱을 개발하다가 현재 페이지에서 useState로 세팅된 값을 넘겨주어야 할 일이 생겼다.

export default function PaymentResult() {
    // ...

    return (
        <TouchableOpacity 
            style={[styles.paymentBtn, styles.btn]}
            onPress={() => {
              if (buyerName === '' || buyerName === null) {
                Alert.alert('배송지 정보 누락', '받는 사람의 이름이 입력되지 않았습니다.');
              } else if (buyerAddr === '' || buyerAddr === null) {
                Alert.alert('배송지 정보 누락','받는 사람의 주소가 입력되지 않았습니다.');
              } else if (buyerAddrDetail === '' || buyerAddrDetail === null) {
                Alert.alert('배송지 정보 누락','받는 사람의 상세 주소가 입력되지 않았습니다.');
              } else if (buyerTel === '' || buyerTel === null) {
                Alert.alert('배송지 정보 누락','받는 사람의 연락처가 입력되지 않았습니다.');
              } else if (pg === '' || pg === null) {
                Alert.alert('결제수단 누락', '결제수단이 선택되지 않았습니다');
              } else {
                // 모든 정보를 가지고
                AsyncStorage.setItem('payment', JSON.stringify({
                  pg: pg,
                  pay_method: 'card',
                  merchant_uid: `ORD-${uid}-userId`,   // 사용자 아이디를 추가
                  name: '카카오 도마 칼 세트',
                  amount: amount,
                  buyer_email: 'kakao@kakao.com',
                  buyer_name: buyerName,
                  buyer_tel: buyerTel,
                  buyer_addr: buyerAddr,
                  buyer_detail_addr: buyerAddrDetail,
                  buyer_postcode: buyerPostcode,
                  app_scheme: 'example',
                  escrow: false
                }));

                // Payment 컴포넌트로 이동
                navigation.navigate('payment');
              }
            }}
         >
          <Text>결제하기</Text>
        </TouchableOpacity>
    )
}

보통 이렇게 AsyncStorage를 사용하는 방법이 있지만


사용자가 결제를 하지 않고 이전 페이지로 돌아간다고 가정할 때 저대로 놔두면 메모리 누수가 발생하게 된다.


그래서 결제 페이지에서 AsyncStorage로 넘겨온 값을 지워주기 위해 removeItem 메소드를 사용했다.


export default function Payment({ navigation }:any) {

    // 결제시 Iamport Module에 전송할 값을 세팅
    const [paymentInform, setPaymentInform] = useState({
        // ...
    });

    // AsyncStorage로 저장해서 받아온 값을 poaymentInfo에 넣어줌.
    const getPaymentInform = async () => {
        let payInform = await AsyncStorage.getItem('payment');
        try {
            if (payInform !== null) {
                setPaymentInform(JSON.parse(payInform));
                // 결제 하지 않고 뒤로 돌아갈 때 메모리 누수 방지
                AsyncStorage.removeItem('payment');
            }
        } catch (err) {
            console.log(err);
        }
    }

    getPaymentInform();

    // Iamport 모듈 실행에 대한 콜백함수
    const callBack = (resp:any) => {
        // ...
    }

    return (
        <>
            {/* Node Module 설치 확인 필(iamport-react-native) */}
            <IMP.Payment 
                userCode={'imp86589899'} 
                data={paymentInform} 
                loading={<Loading />}
                callback={callBack}
            />
        </>
    )


}

결제가 이루어질 때 callback을 실행해야 하는데, resp로 넘어온 값 중에 imp_successtrue인 경우와 false인 경우로 나눠서 작업을 처리할 콜백함수가 필요하다.


원래는 nativation.replace()를 사용해서 페이지 이동을 해주어야 하지만, 위에서 removeItem을 했기 때문에 AsyncStorage.getItem('payment')를 사용할 수 없다.


그래서 navigation.navigate()로 넘겨주는 대신 객체형태로 값을 전달하게 해준다.


// Iamport 모듈 실행에 대한 콜백함수
const callBack = (resp:any) => {
    // console.log(resp);
    if (resp.imp_success === 'true') {
        navigation.navigate('paymentResult', {"key": paymentInform});
        //navigation.replace('paymentResult', resp);        // 원래 방법
        //navigation.navigate('paymentResult', JSON.stringify(paymentInform));      // JSON.stringify로 해도 안됨...

    } else {
        navigation.replace('paymentFailed', resp);
    }
}

결과 화면에서 { route }가 매개변수로 들어가야하고 route로 접근해서 params.key로 빼올 수 있다.


export default function PaymentResult({ navigation, route }:any) {

    /* 
        Payment 컴포넌트에서 Iamport 모듈의 data 속성에 전달해주는 값을 그대로 가져온다.
        Payment 컴포넌트에서 사용자가 임의로 결제를 취소하는 경우 메모리 누수가 발생하므로
        이를 방지하기 위해 AsyncStorage가 remove되도록 했기 때문에 값을 가져올 수 없다.
        이 때 data에 넣어주는 값은 JavaScript 객체이고, 이 값을 PaymentResult로 가져오기 위해
        Iamport의 콜백함수에서 navigate 메소드에 data를 전달하는데, key-value 형태로 값을 가져와야 이 컴포넌트에서 불러올 수 있다.
        그냥 getter로 전달하려고 했더니 안된다...
    */

    const paymentData = route.params.key;
    console.log(paymentData);

    // 결제 성공시 배송 및 주문 정보를 axios로 백엔드에 넘겨서 처리
    useEffect(() => {
        axios.post('http://192.168.0.13:3000/payment/addGoodsShoppingList', null, 
        {
            params: {
            memberId: paymentData.buyer_name,
            paymentPay: paymentData.amount,
            paymentMainAddr: paymentData.buyer_addr,
            paymentDetailAddr: paymentData.buyer_detail_addr,
            paymentZipcode: paymentData.buyer_postcode
        }})
        .then((res) => console.log(res.data))
        .catch((err) => console.log(err));
    }, [])


    return (
        <View style={styles.container}>
            <Text style={styles.title}>결제가 완료되었습니다!</Text>
            <View style={styles.btnGroup}>
                <TouchableOpacity 
                    style={[styles.btn, styles.btnPrimary]}
                    // onPress={() => navigation.navigate("Home")}
                >
                    <Text style={styles.btnText}>상세 주문 정보</Text>
                </TouchableOpacity>
                <TouchableOpacity 
                    style={[styles.btn, styles.btnBack]}
                    onPress={() => navigation.navigate("Home")}
                >
                    <Text style={styles.btnText}>계속 쇼핑하기</Text>
                </TouchableOpacity>
            </View>
        </View>
    )
}