
나는 예전에 사용해서 익숙한 firestore database 에서 데이터를 관리하려고 한다

데이터 입력은 직접 필드를 입력해서 만들었고
오늘은 이렇게 만든 데이터를 프로젝트로 가져올것이다
간단하게 차 번호, 출입 시간, 사진 정보를 기록했다
| Document ID | car_number | timestamp | imgUrl |
|---|---|---|---|
| EB453ecMlL7MAI6CcMO2 | 33가3333 | 2025-02-13 19:39:15 | https://firebasestorage.googleapis.com/v0/b/parking-management-2cba1.firebasestorage.app/o/images%2F3333.png |
| XPF241ctPORR3kFlVJVz | 66나6666 | 2025-02-13 19:39:25 | https://firebasestorage.googleapis.com/v0/b/parking-management-2cba1.firebasestorage.app/o/images%2F6666.png |
| stleQ7ub75uN7LABXcrj | 22바2222 | 2025-02-13 19:35:13 | https://firebasestorage.googleapis.com/v0/b/parking-management-2cba1.firebasestorage.app/o/images%2F2222.png |
원래 공식문서 보는거 무서워 하는데
여기는 공식문서가 잘되어 있어서 참고해서 코드를 작성했다
firebase 초기화한 파일에 db 초기화 코드도 추가해주기
import { getFirestore } from "firebase/firestore";
const db = getFirestore(app);
// 전체 코드
import { initializeApp } from "firebase/app";
import { getFirestore } from "firebase/firestore";
import { getAuth } from "firebase/auth";
const firebaseConfig = {
apiKey: import.meta.env.VITE_FIREBASE_API_KEY,
authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN,
projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID,
storageBucket: import.meta.env.VITE_FIREBASE_STORAGE_BUCKET,
messagingSenderId: import.meta.env.VITE_FIREBASE_MESSAGING_SENDER_ID,
appId: import.meta.env.VITE_FIREBASE_APP_ID,
measurementId: import.meta.env.VITE_FIREBASE_MEASURE_MENT_ID,
};
const app = initializeApp(firebaseConfig);
const db = getFirestore(app);
const auth = getAuth(app);
export { app, db, auth };
공식문서 - 문서 가져오기 에 있는 코드를 그대로 복사해 온 후
내 프로젝트에 맞게 컬렉션 부분을 수정했다
import { collection, getDocs } from "firebase/firestore";
import { app, db } from "../firebase";
const querySnapshot = await getDocs(collection(db, "parking_records"));
querySnapshot.forEach((doc) => {
// doc.data() is never undefined for query doc snapshots
console.log(doc.id, " => ", doc.data());
});
이게 비동기 작업이다 보니 await이 사용됐다
await은 async 안에서만 사용가능하니 async 도 적어주기
export default async function Settlement() {
const querySnapshot = await getDocs(collection(db, "parking_records"));
querySnapshot.forEach((doc) => {
console.log(doc.id, " => ", doc.data());
});
}
Settlement' cannot be used as a JSX component.
Its return type 'Promise<Element>' is not a valid JSX element.
Type 'Promise<Element>' is missing the following properties from type 'ReactElement<any, any>': type, props, key
이 에러는 컴포넌트를 async 함수로 작성했기 때문에 발생한 에러라고 한다
async 함수는 항상 Promise를 반환하는데
리액트 컴포넌트는 JSX 요소를 반환해야 하기 때문이다
결국 await를 최상위 레벨에서 사용하려다 보니 컴포넌트를 async로 감쌌고
이로 인해 Promise를 반환하게 되어 위와 같은 오류가 발생한 것
이런 경우 useEffect 훅을 사용하면 된다고 한다
약간 꼼수 같은건데 위에 함수를 정의해놓은 뒤
처음 컴포넌트가 로드될때 함수를 호출해서 실행시키기
useEffect(() => {
const loadParkingRecords = async () => {
try {
const querySnapshot = await getDocs(collection(db, "parking_records"));
querySnapshot.forEach((doc) => {
console.log(doc.data());
});
} catch (error) {
console.error(error);
}
};
loadParkingRecords();
}, []);
이렇게 불러온 데이터를 상태로 저장하기 위해
데이터 타입을 interface 로 정의해 놓기
interface ParkingRecordType {
car_number:string;
timestamp:string;
imgUrl:string;
}
const [parkingRecords, setParkingRecords] = useState<ParkingRecordType[]>([]);
useEffect(() => {
const loadParkingRecords = async () => {
try {
const querySnapshot = await getDocs(collection(db, "parking_records"));
querySnapshot.forEach((doc) => {
setParkingRecords((prev)=>[...prev,doc.data()])
});
} catch (error) {
console.error(error);
}
};
loadParkingRecords();
}, []);
Argument of type '(prev: ParkingRecordType[]) => DocumentData[]' is not assignable to parameter of type 'SetStateAction<ParkingRecordType[]>'.
Type '(prev: ParkingRecordType[]) => DocumentData[]' is not assignable to type '(prevState: ParkingRecordType[]) => ParkingRecordType[]'.
Type 'DocumentData[]' is not assignable to type 'ParkingRecordType[]'.
ParkingRecordType[] 어쩌고.. 내가 이상하게 타입을 지정했나?
또 DocumentData[] 는 뭐지 하고 검색 해봤더니

이렇게 공식문서에 DocumentData 란 인터페이스가 따로 있었고
눈치껏 이걸로 바꿔봤더니 문제가 해결됐다
import { getDocs, collection,DocumentData } from "firebase/firestore";
const [parkingRecords, setParkingRecords] = useState<DocumentData[]>([]);
그 후 렌더링에서 2개씩 출력되는 문제 발생

이건 리액트의 strict mode 때문이었다
strict mode 는 개발중에 코드가 의도한대로 작동하는지 확인하기 위해
일부 컴포넌트의 렌더링을 두 번 호출하는 데 그 때문에 2개씩 출력됐던 것이다
이건 그냥 <React.StrictMode> 코드를 지워주면 해결된다
