react에서 api 호출 시 비동기 문제 처리 방법

sig03
5 min readJul 2, 2021

--

# 시나리오

  • react에서 api를 호출해 값을 받아온다.
  • 받아온 값을 hook을 사용해 업데이트 한다.
//App.jsimport React, { useState, useEffect, useRef } from 'react';
import { getValue } from './api/File';
function App() {
const [check, setCheck] = useState('');
useEffect(() => {
const returnValue = getValue();
setCheck(returnValue);
},[]);
return (
<div>
value : {check}
</div>
);
}

export default App;
//./api/File.jsimport axios from 'axios';export const getValue = () => {

axios({
method: 'GET',
url: '
http://URL',
}).then(function(res) {
if (res.data.result === "F") {
return 'F';
} else {
return 'S';
}
});
}

위와 같은 소스가 있다고 하자. File.js 파일에 api가 있다. App.js에서 axios로 값을 불러오고 불러온 값을 useState인 setCheck로 세팅해서 jsx에 뿌려준다. 결과가 어떻게 나올까? 원하는 시나리오대로 check 값이 제대로 나올까? 정답은 X.

안되는 원인이 뭘까? api 값을 찍어보면 값은 정상적으로 호출한다. 하지만 html에는 값이 안찍힌다. 이는 자바스크립트가 비동기 언어라서 그렇다. api 의 호출을 기다리지 않고 일단 html을 뿌려버린다. 그 이후에 api 값을 찍는다. 순차적으로 소스 코드가 진행되서 api 호출 후 다음 과정이 진행될 것 같지만 비동기라 api는 나중에 호출된다. api 호출 타이밍을 기다려주지 않는 것이다. 원인은 자바스크립트의 비동기성 때문에 발생한 타이밍 문제였다.

방법을 몰라서 문제를 아래와 같이 해결했었다. api 에서 axios 객체만 리턴해주고 그걸 App.js에서 받아 처리하는 방법. 이렇게 했을때 되는 이유가 then 이후 구문 때문일 것 같은데 이게 api 쪽에 붙어 있으면 객체를 만들고 호출하고 이렇게 2단계로 진행되서 값을 제때 못찍고, then 구문이 App.js 쪽에 붙어 있으면 만들어진 객체를 바로 처리해서 1단계로 진행되 동시성 문제가 해결되는게 아닌가 하는 뇌피셜을…

//App.jsuseEffect(() => {
const returlValue = getValue();
returnValue.then(function(res) {
if (res.data.result === "F") {
console.log(res);
} else {
setCheck(res.data.info);
}
});
},[]);
//./api/File.jsimport axios from 'axios';export const getValue = () => {

return axios({
method: 'GET',
url: '
http://URL',
});
}

어쨌건 기존 문제가 자바스크립트의 비동기 문제, 타이밍 문제라는걸 알았기 때문에 좋은 해결책은 async, await 를 사용하는 것이다. async, await 는 api 쪽이 아니라 App.js 쪽에 선언되어야 한다. 동시성을 맞추는게 App.js 쪽이지 File.js 쪽이 아니기때문. 이렇게하면 페이지 호출 시 api 를 불러온 값을 세팅하고 원하는대로 check 값을 찍을 수 있다.

import React, { useState, useEffect } from 'react';
import { getValue } from './api/File';
function App() {
const [check, setCheck] = useState('');


const load = async () => {

const returnValue = await getValue();
setCheck(returnValue)

}

useEffect(() => {
load()
},[]);




return (
<div>
value : {check}
</div>
);
}

export default App;
//./api/File.jsimport axios from 'axios';export const getValue = () => {

axios({
method: 'GET',
url: '
http://URL',
}).then(function(res) {
if (res.data.result === "F") {
return 'F';
} else {
return 'S';
}
});
}

위와 같은 방법이 소스 코드가 훨씬 깔끔해지는데 작업하다보니 최초 방법이랑 소스코드 양이 거의 비슷하거나 오히려 늘어서 그냥 then 구문을 활용하는 방법을 그대로 두고 쓰고 있다.

--

--

sig03
sig03

No responses yet