개발/STUDY

React에서 데이터 요청

송디 2024. 5. 24. 21:49

- Axios와 Fetch, 나의 선택은? 

데이터를 API 요청으로 받을 시간이 왔다.  Axios를 사용한 기억이 있는데, fetch가 있다고 한다. 둘 중에 뭐를 사용하면 좋을까? 아무래도 API 요청은 핵심적인 기능이고 자주 사용하다보니 잘 선택하고 싶다. 일단 둘을 비교해보자.

기능/특성 fetch axios
설치 필요 여부 브라우저 내장 별도 설치 필요
기본 기능 네트워크 요청 기능만 제공 JSON 파싱, 상태 코드 처리, 요청 취소 등 다양한 기능 포함
에러 핸들링  네트워크 에러만 캐치, 상태 코드 에러 직접처리 필요 모든 에러 자동 처리
요청 취소 AbortController 사용 기본 제공
응답 데이터 변화 수동으로 변환(ex. response.json()) 자동변환(JSON 데이터)

 

fetch는 브라우저 내장이 가장 큰 매력일 것 같다. 프로그램의 무게를 줄이고 싶어 fetch를 선택했는데, 막상 에러처리와 같은 부분에서는 response 의 상태코드가 200이 아니더라도 반환하기 때문에, 이를 처리하는 과정도 꽤나 번거로웠다. axios는 자동으로 처리해주니 다음에는 사용을 고려해봐야 겠다. 

 

async function createPayment(token, req){
  try {
    // POST 요청을 보내기 위한 설정
    const requestOptions = {
      method: 'POST',
      headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${token}`,
      },
      body: JSON.stringify(req), 
    };

    const response = await fetch(apiUrl + 'order/v1/payments', requestOptions);
    const data = await response.json();
    console.log(data);
    if (!response.ok) {
      throw data.error_code;
    }

    return data;
  } catch (error) {
    console.error('데이터를 가져오는 중 오류 발생:', error);
    throw error;
  }
}

 

위 코드는 유저가 결제 버튼을 누를 때 payment 를 생성하는 요청하는 것이다. requestOptions에 method나 header 그리고 body를 넣는다. 그리고 fetch를 통해 request 한다. async/await를 사용하여 비동기로 처리해준다. 응답이 오면 response에 데이터가 할당되고, 이 response가 200이 아니면 error를 던지도록 한다. 그 외 제대로 왔으면 response를 json으로 바꾸어주고 이를 반환한다. 

 

- 데이터를 받는 시간 동안 유저는 떠나.. Loading 페이지 추가 

 데이터를 비동기로 받을 때, 요청을 클릭하고 사용자 환경에 따라 지연이 발생한다. 이 때, 화면에 변화가 없으면 유저는 다시 버튼을 클릭한다. 사실 나는 몇 초 후에 버튼을 누를 줄 알았지만, 유저 테스트를 통해 지켜본 바, 거의 1초가 되기전 다시 누른다... 그래서 지연이 발생하는 데이터 송 수신 쪽은 Loading page가 필요했다. Loading Page를 추가함으로써 훨씬 자연스러운 UX가 완성된다. 


const Login = () => {
...

    const login = async () => {
        if (checkInfo()) {
            setIsLoading(true);
            try {
                setPersistence(firebaseAuth, browserLocalPersistence)
                    .then(() => signInWithEmailAndPassword(firebaseAuth, userEmail, userPassword))
                    .then(async (userCredential) => {
                        if (userCredential) {
                            try {
                                await generateToken(userCredential.user);
                            } catch (error) {
                                console.log(error);
                                throw error;
                            }
                        } else {
                            alert("다시 로그인을 시도해주세요.");
                        }
                    })
                    .then(() => {
                        setIsLoading(false);
                    })
                    .then(()=>{
                        navigate('/', { state: { snackBar: true } });
                    })
                    .catch((error) => {
                        console.log(error);
                        setIsLoading(false);
                        const errorCode = error.code;
                        switch (errorCode) {
                            case 'auth/user-not-found':
                                setErrMsg('입력한 아이디는 없는 아이디입니다.');
                                break;
                            case 'auth/wrong-password':
                                setErrMsg('비밀번호가 일치하지 않습니다.');
                                break;
                            case 'auth/invalid-login-credentials':
                                setErrMsg("아이디 혹은 비밀번호 정보를 정확하지 않습니다.");
                                break;
                            default:
                                setErrMsg("로그인에 실패하였습니다. 이메일 인증을 진행했는지 확인해주세요.");
                        }
                    });
            } catch (err) {
                console.log(err.code);
                alert("로그인에 실패하였습니다.");
                setUserEmail('');
                setUserPassword('');
                setIsLoading(false);
            }
        }
    }
...
    return(
        <div id="child">

            <Snackbar 
                open={open} 
                onClose={() => setOpen(false)} 
                message="회원가입에 성공하였습니다. 가입하신 이메일로 이동하셔서 인증을 하셔야 정상적으로 로그인 할 수 있습니다."
                autoHideDuration={6000}
                anchorOrigin={{vertical: 'bottom', horizontal: 'center'}}
            />
            {isLoading ? <LoadingScreen></LoadingScreen> : 
            
                ...
    )
}

export default Login;

 

위 코드를 보면 로그인을 시작 할 때, isLoading이라는 값을 true로 바꾸고 화면에는 LoadingScreen 컴포넌트가 마운트 되며 보여진다. 그리고 로그인이 마무리 될 때, isLoading은 false가 되고 화면에는 LoadingScreen 컴포넌트가 언마운트 되어진다. 

728x90

'개발 > STUDY' 카테고리의 다른 글

useEffect  (0) 2024.05.26
React 파일 구조  (0) 2024.05.25
CSR과 SSR  (0) 2024.05.23
브라우저 동작 방법  (0) 2024.05.23
프로토타입  (0) 2024.05.23