본문 바로가기

Web

[React] 동기와 비동기 / async와 await

728x90

 

 

 

동기/비동기 기준이 헷갈려서 고생했다.

 

axios.get()으로 데이터를 받아오고, 이 데이터를 기반으로 html 요소를 생성하는 중인데 동기식으로 처리하기 위해 async&await을 사용함에도 계속 변수에 null값 밖에 들어가지 않는 상태였다...

대체 why

 

 

기존 코드는 아래와 같다.

const getAllPost = async () => {
    const res = await axios.get('/main');
    items = res.data;
}
useEffect(() => {
    getAllPost();
}, []);
    
console.log(items);
(items ? keys = Object.keys(items) : console.log("items is null"))

 

분명 위에서 기다리라고 했는데! 계속 아래 코드가 실행되어 "items is null"만 출력되었다...

 

 

비동기와 동기 처리에 대해 잘못 이해하고 있었기 때문에 이런 일이 발생했다.

 

 

  동기 / 비동기 기준

리액트는 기본적으로 비동기식으로 코드를 처리한다고 알고 있다. 이 때문에 특정 구간을 동기식으로 처리하고 싶다면 async와 await을 사용해야 한다.

그러나 async로 묶여있는 구간(함수 블럭 등)만 동기식으로 처리하겠다는 것이지, 그 외에는 여전히 비동기식으로 처리가 된다. 

따라서 위 코드는 

여기서 get 요청에 대기하고 있어도

const res = await axios.get('/main');

 

동시에 아래 코드가 실행되어 수많은 오류를 생산했던 것이다...

console.log(items);
(items ? keys = Object.keys(items) : console.log("items is null"))

 

 

이는 원하는 데이터를 받아올 때까지 기다려야 하는 변수들을 async 블럭에 넣어주면서 해결되었다.

const getAllPost = async () => {
    const res = await axios.get('/main');
    items = res.data;
    console.log(items);
    (items ? keys = Object.keys(items) : console.log("items is null"))
}
useEffect(() => {
    getAllPost();
}, []);

 

굿

 

  + 이 코드는 아니야...

items에 값은 잘 받아오는데 re-rendering을 위해 keys만 state를 이용한 관리를 했다.

그러자 내가 값을 넣은 items가 다음 rendering에서는 null이 되어 나타났다... 다른 객체가 되어버린 것이다.

 

 

  + GPT

 

gpt한테 물어봤을 때는 state를 이용해 데이터의 변화를 감지하도록 하라고 안내해주었다.

const getAllPost = async () => {
        const res = await axios.get('/main');
        setItems(res.data);
        
    }
    useEffect(() => {
        getAllPost();
    }, []);
    useEffect(() => {
        if (items) {
            console.log("items:", items);
            setKeys(Object.keys(items));
        } else {
            console.log("items is null");
        }
    }, [items]);

 

 

gpt의 정확한 설명...

 

이전에 이미 비동기에 대해 친절히 설명해주었지만 내가 잘 못 알아들었다...

 

 

  최종 코드

 

const [items, setItems] = useState(null);
const [keys, setKeys] = useState(null);

const getAllPost = async () => {
    const res = await axios.get('/main');
    setItems(res.data);
    setKeys(Object.keys(res.data));
    console.log(items);
}
useEffect(() => {
    getAllPost();
}, []);

 

state가 너무 re-rendering을 많이 부르는 것 같아 사용하지 않으려고 해봤지만, 그렇게 하면 강제 렌더링을 실행시켜야 하기 때문에 그냥 state를 사용하기로 결정했다.

 

state를 사용하지 않으면

async 대기 -> return 실행 -> async 종료 -> 다음 코드 실행

 

이런 순서로 실행이 되어서 내가 의도한 async 이후 return이 실행되는 작업이 되지 않았다.

state를 이용해 items에 값이 들어온 이후, re-rendering을 통해 다시 코드를 실행할 수 있도록 했다.

 

 

  forEach와 map

json을 반복하며 게시글을 html에 동적으로 생성하는데, 처음에는 json객체에 map을 직접적으로 쓸 수 없어 forEach를 사용했다.

아무리 해도 html이 생성되지 않았다...

gpt한테 물어보니 forEach는 반환을 하지 않는단다. 그래서 return을 작성해도 반환 작업이 되지 않았었다.

json을 Object.keys을 이용해 인덱스로 뽑고, map과 index를 이용해 json에 접근, 반환을 해주니 잘 출력되었다.

해결해서 다행이다

 

지피티 답답할 때도 있지만, 척척박사다. 학사인 나보다 나은듯 ㅋ