업로드하기 버튼을 누르면 작성한 data 가 db로 올라가고 (Create)
동시에 옆에 있는 카드에 data 가 불러와지는 (Read)
SPA (새로고침 없이 작동하는) 를 만들고자 했다.
Create : 새로운 data 를 만드는 것에는 save_writing 함수를,
Read : 만들어진 data 리스트를 불러오는 것에는 getPostList 함수를 사용했다.
업로드 버튼을 onclick 하면 두 함수가 불러와지도록 만들었다.
업로드 하기를 누르면 DB 인 firestore 에는 정상적으로 올라가는데,
새로고침을 해야만 옆의 카드에 새로 생성된 data 가 들어왔다.
일단 save_writing 은 잘 작동하고 있으니
getPostList 가 data 리스트를 잘 불러오는지 확인을 위해 console을 쳤다.
정상적으로 값이 들어오는 것을 보아 Firebase 연결의 문제는 아니었다.
알고보니 save_writing 과 getPostList 이 비동기 함수로 각각 실행되고 있었다.
동기 함수란,
함수 A와 함수 B를 호출할 때, 함수 A가 함수 B의 리턴값을 계속 확인하면서 신경 쓰는것을 말한다.
B가 끝나야만 A함수가 작업을 완료할 수 있는 것이다.
반대로 비동기 함수란,
함수 A와 함수 B를 호출할 때, 함수 A가 함수 B의 작업 완료 여부는 신경 쓰지 않는 것을 말한다.
한마디로 다른 함수가 끝나던 말던 신경 안쓰고 각각 마이웨이로 작업을 처리한다는 뜻.function cureDisease(human, medicine) // 인자로 받은 medicine으로 human을 치료한다. function getMedicine() // 치료에 필요한 medicine을 리턴한다. // // 동기 const human = new Human() const medicine = getMedicine() cureDisease(human, medicine) // --> getMedicine 함수가 완료된 후에 cureDisease 가 완료됨 // // 비동기 const human = new Human() console.log('human 병 걸림') getMedicine({ params: {}, success: function (medicine) { cureDisease(human, medicine) } }) console.log('human 병 치료됨') // --> 'human 병 걸림' > 'human 병 치료됨' > getMedicine 함수 완료 // --> getMedicine 함수 완료여부와 상관없이 console.log('human 병 치료됨') 진행 // $.ajax()
따라서 비동기로 각각의 함수가 실행되면, 아래와 같은 프로세스가 되는데,
getPostList 완료 ( = 이전 data 리스트 불러옴)
--> save_writing 완료 ( = 새로운 data 가 DB에 저장됨)
--> 새로고침
--> 새로운 data 리스트 불러옴
이렇게 되면 새로운 data 를 만드는 save_writing 완료 여부와 상관없이
만들어진 data 리스트를 불러오는 getPostList 가 실행되고 완료되기 때문에
save_writing 가 다 완료되기 전 getPostList 가 완료되어서
새로고침 전에는 새로운 data가 적용되지 않은 리스트만이 보여진다.
( 물론 어떤 함수가 빨리 완료될지는 항상 다르기 때문에
같은 동작을 반복하면 어쩌다 한 번쯤은 우리가 원하는 순서대로 작동돼
새로고침하지 않아도 새로운 data 리스트가 불러와질 수도 있다.)
때문에 비동기 함수를 동기로 바꾸어주는 작업이 필요하다.
save_writing이 완료된 후에야 save_writing 이 완료되도록 하려면
async과 await 로 save_writing 를 save_writing 에 삽입해
동기 함수의 작동 순서를 지정할 수 있다. await 를 붙여 이 함수가 끝날 때까지 기다리게 하는 것이다.
참고 자료 : async와 await
[save_writing 에 await 추가 전 ]
[save_writing 에 await 추가]
[완성된 save_writing 함수]
export const save_writing = async (event) => {
event.preventDefault();
const imgRef = ref(
storageService,
`${authService.currentUser.uid}/${uuidv4()}`
);
const imgDataUrl = localStorage.getItem("imgDataUrl");
let downloadUrl;
if (imgDataUrl) {
const response = await uploadString(imgRef, imgDataUrl, "data_url");
downloadUrl = await getDownloadURL(response.ref);
}
const coverInput = downloadUrl ? downloadUrl : null;
const artistName = document.getElementById("artistName");
const songName = document.getElementById("songName");
const title = document.getElementById("title");
const hashTag = document.getElementById("hashTag");
const bodyText = document.getElementById("bodyText");
const emojiSelect = $('input[name="emoji"]:checked').val();
const { uid, photoURL, displayName } = authService.currentUser;
try {
await addDoc(collection(dbService, "Writings"), { <<<---- 여기
coverInput: coverInput,
artistName: artistName.value,
songName: songName.value,
emotion: emojiSelect,
title: title.value,
hashTag: hashTag.value,
bodyText: bodyText.value,
createdAt: Date.now(),
creatorId: uid,
profileImg: photoURL,
nickname: displayName,
}).then(() => {
alert("포스트 업로드 완료");
});
await getPostList(event); <<<---- 여기
} catch (error) {
alert(error);
console.log("error in addDoc:", error);
}
};
자세히 살펴보면 save_writing 내부에 await addDoc, await getPostList 가 들어가 있다.
await 가 쓰인 함수들이 완료되어야만 save_writing 가 작동한다.
이렇게 바꾸고 나니 업로드하기를 눌렀을 때 새로고침 없이 새로운 데이터 리스트가
잘 가져와 지는 것을 확인할 수 있었다.