July 16, 2021
컴포넌트 내, mount시에만 실행시키고 싶은 effect를 custom hooks로 만들었다. effect 내에서 사용되어야 하는 값들을 dependencies array에 추가해주니 array 내에 포함된 값이 변경될 때 뿐만 아니라, 컴포넌트 내 다른 state가 변경되어 re-render 될 때마다 effect가 실행되고 있었다. 🤔
이 hooks에서는 데이터를 fetch 후 action 을 dispatch 하는 로직이 있었는데 action이 불필요하게 자주 dispatch 되는 걸 보고 알 수 있었다.
그렇다고 dependencies array 를 []
로 넣어주니 React가 useEffect에 dependency가 빠졌다고 필요한 것들 다 array에 추가하던지 아니면 array를 없애던지 둘 중에 하나를 하라는 warning을 보여줬다; (둘 다 내가 원하는게 아닌데..)
찾아보니 useRef, useState로 didLoad 같은 값을 만들어서 useEffect 내에서 한번만 실행되게 만드는 방법을 알려줬다. 과연 이 방법이 최선일까?
궁금증 1 dependencies array가 [] 일 때는 mount 후에 한번 로직이 실행되는 거라 이해하지만, dependecies array에 특정 값이 있을 때는 왜 컴포넌트가 re-render 될 때마다 useEffect가 실행되는 걸까?
궁금증 2 mount 시에만 redux action을 dispatch 해야 하는 경우 didLoad 같은 값을 만들어서 !didLoad 일때만 로직을 실행시키도록 하는 방법 외에 뭐가 있을까?
내가 잘못하고 있었던 점
useEffect 내에서 사용하는 값은 folder.folderId
, folder.resourceList
였는데 dependencies array에 folder
를 넣어주고 있었다. 제대로 위의 값들을 넣어주니 불 필요하게 useEffect가 실행되지 않았다.
// NO
const useCheck = folder => {
useEffect(() => {
if (folder.folderId) {
getAddedByExtension(folder.resourceList)
}
}, [folder])
}
// YES!
const useCheck = folder => {
useEffect(() => {
if (folder.folderId) {
getAddedByExtension(folder.resourceList)
}
}, [folder.folderId, folder.resourceList])
}
dependencies array에 object를 넣어주면 object의 reference를 비교해서 effect를 실행시킬지 말지 판단한다. 하지만 object가 새로 생성되었는지 아닌지는 보장하지 못한다. object 내의 몇 가지 properties 들을 사용하고 있고 그 값이 primitive type 이기 때문에 이 값들을 dependencies array에 추가해줘야 한다.
useEffect 내에서 사용하는 object 값들을 위해 object를 넘겨주지 말고, 정확한 property 들을 dependency array에 추가하자.
참고: https://www.benmvp.com/blog/object-array-dependencies-react-useEffect-hook/
트랜잭션은 여러 개의 get()
작업과 이어서 수행되는 set()
, update()
, delete()
등의 여러 쓰기 작업으로 구성된다. 동시 수정의 경우 Firestore에서는 전체 트랜잭션을 다시 실행한다. 예를 들어 한 트랜잭션에서 문서를 읽고 다른 클라이언트가 그 문서를 수정하는 경우 Firestore는 해당 트랜잭션을 다시 시도한다. 그래서 트랜잭션이 항상 일관된 최신 데이터로 실행됩니다.
runTransaction (updateFuction : (transaction) => Promise ): Promise
const sfDocRef = db.collection('cities').doc('SF')
return db.runTransaction(transaction => {
return transaction // transaction.get(documentRef) : DocumentSnapshot
.get(sfDocRef)
.then(sfDoc => {
if (!sfDoc.exists) {
throw 'Document does not exist'
}
let newPopulation = sfDoc.data().population + 1
transaction.update(sfDocRef, { population: newPopulation })
})
.then(() => {
console.log('Transaction successfully committed')
})
})
여러 문서를 query 하는 경우
const museumsQuery = db.collection('landmarks').where('type', '==', 'museum') // [where return Query](https://firebase.google.com/docs/reference/js/firebase.firestore.Query#where)
museumsQuery.get().then(querySnapshot => {
querySnapshot.forEach(doc => {
console.log(doc.id, '=>', doc.data())
})
})
docs
property나 forEach method로 array 처럼 접근할 수 있다..data()
또는 .get(field)
로 데이터를 가져올 수 있다.=