#문제
▶ 이미지를 첨부하고 [등록하기] 버튼을 누르면
fireStorage에 사진을 저장 & FireStore DB에 url 저장 기능 구현을 하고 싶은데
FireStore DB에 image_url이 저장되기 전에, 동기 부분이 완료되서 image_url 저장이 안됨.
#해결
▶ FireStore에 데이터가 저장되기 전에 이미지 파일 업로드가 우선 실행되도록 위치로 조정
▶ 이미지 저장이 끝나고 FireStore에 데이터 저장되도록 async + await 코드로 수정
[Inputform.jsx]
//이미지 파일 업로드
const handleUpload = async () => {
const imageRef = ref(storage, `${auth.currentUser.uid}/${selectedFile.name}`);
try {
await uploadBytes(imageRef, selectedFile);
// 저장된 image url :getDownloadURL(imageRef)
return await getDownloadURL(imageRef);
} catch (erro) {
console.log('Inputform.jsx (handleUpload): ', erro);
throw error;
}
};
<form onSubmit={async (event) => {
event.preventDefault();
try {
if (window.confirm('새글을 등록하시겠습니까?')) {
//1. 이미지 파일 업로드
const uploadImageUrl = await handleUpload();
//2. 모달창에 입력된 새로운 데이터
const newData = {
email: 'test',
content,
store,
date: new Date(),
title,
image_url: uploadImageUrl
};
setData((prev) => [newData, ...prev]);
//3. 파이어스토어에 데이터 저장
const collectionRef = collection(db, 'newData');
await addDoc(collectionRef, newData);
setModalOpen(false);
} else { return;}
}
catch (Error) {
console.log('Inputform.jsx (form Error): ', Error);
}
}}
>
#Done
1) 모달팝업으로 만들기
2) 로그인 여부 판단 : 로그인한 사람만 새글 작성 간으
3) 파일 업로드 기능 추가하기 (파일 저장 : fireStorage + 파일 url : FireStore DB )
4) [등록하기] 버튼 : 저장 후 팝업닫기
5) [닫기] 버튼 : 확인 후 닫기 진행
6) 모달팝업은 하이라이트 & 배경은 흐리게 설정
7) 글 작성시 버튼 클릭시 테두리 하이라이트 설정
#Todo
1) props로 데이터 전달하는 부분 redux로 수정
1) [닫기] & [등록하기] 버튼 클릭시 모달팝업으로 처리
2) 작성자는 이메일말고 작성자 이름 또는 닉네임 처리 ( 미정 )
1. <InputformLayout.jsx > : 메인 레이아웃 페이지
- firestore에 저장된 데이터 가져오기 : await getDocs(query(colleciont(db,'db name')));
- 모달(modal) 상태 : const [modalOpen, setModalOpen] = useState(false);
- 로그인 여부 판단 : <Auth> 컴포넌트 에서 로그인한 아이디 정보 update
//로그인 정보 -- 로그인한 사용자가 댓글을 달 수 있도록
const [currentEmail, setCurrentEmail] = useState('');
const showModal = () => {
//로그인 여부 체크 (자료형 false 반환 : "",null,undefined,0 NaN)
if (!currentEmail) {
alert('로그인하셔야 새글 작성이 가능합니다.');
return;
}
setModalOpen(true);
};
- <Auth> 컴포넌트 : 회원가입/로그인/로그아웃 기능
- <Button> 컴포넌트: 클릭시 모달창 오픈 기능
- <Modal> 컴포넌트 : 모달 상태값 true (modalOpen) && props : ( currentEmail : 현재로그인된 이메일) 전달
2. <Auth.jsx > : 회원가입 / 로그인 / 로그아웃 기능 + 현재 로그인된 이메일 정보
//현재 로그인한 사용자 가져오기
useEffect(() => {
//(onAuthStateChanged)
// 인증 객체의 상태변화 감지 리스너 (로그인/로그아웃)
auth.onAuthStateChanged((user) => {
setCurrentEmail(user ? auth.currentUser.email : '');
});
}, [currentEmail]);
- 현재 로그인된 이메일을 여기서 setCurrentEmail로 상태 업데이트
const signUp = async (event) => {
event.preventDefault();
try {
const userCredential = await createUserWithEmailAndPassword(auth, email, password);
console.log('user', userCredential.user);
} catch (error) {
const errorCode = error.code;
const errorMessage = error.message;
console.log('error with signUp', errorCode, errorMessage);
}
};
- 회원가입기능 : 이메일과 비밀번호로 회원가입 가능
const signIn = async (event) => {
event.preventDefault();
try {
const userCredential = await signInWithEmailAndPassword(auth, email, password);
console.log('user with signIn', userCredential.user);
} catch (error) {
const errorCode = error.code;
const errorMessage = error.message;
console.log('error with signIn', errorCode, errorMessage);
}
};
const logOut = async (event) => {
event.preventDefault();
await signOut(auth);
};
-로그인 & 로그아웃 기능
3. <Modal.jsx > : 클릭시 모달창 오픈 기능
- 마우스 hover 시 하이라이트 되도록 설정
&:hover {
border: 1px solid #7579e7;
box-shadow: rgba(117, 121, 231, 0.4) 0px 0px 0px 3px;
}
function Modal({ setModalOpen, setData, currentEmail }) {
const closeModal = () => {
setModalOpen(false);
};
return (
<BackGround>
<Container>
<Button onClick={closeModal}>닫기</Button>
<Inputform setData={setData} currentEmail={currentEmail} setModalOpen={setModalOpen} />
</Container>
</BackGround>
);
}
- styled-component 구성
<BackGround> Div : 모달창 오픈시 뒤에 흐려지는 부분 포인트 (4가지)
: background-color: rgba(0, 0, 0, 0.5);
: backdrop-filter: saturate(180%) blur(8px);
: z-index: 10;
: position: fixed;
<Container> Div : 메인 모달창 포인트 (2가지)
: z-index: 100;
: position: absolute;
- <InputForm> 컴포넌트 : 모달창 내용 부분
4. <Inputform.jsx > : 새 글 작성 후 fireStorage에 저장 + 이미지 파일 올리기
//이미지 파일 업로드
const handleUpload = async () => {
const imageRef = ref(storage, `${auth.currentUser.uid}/${selectedFile.name}`);
try {
await uploadBytes(imageRef, selectedFile);
// 저장된 image url :getDownloadURL(imageRef)
return await getDownloadURL(imageRef);
} catch (erro) {
console.log('Inputform.jsx (handleUpload): ', erro);
throw error;
}
};
return(
<form onSubmit={async (event) => {
event.preventDefault();
try {
if (window.confirm('새글을 등록하시겠습니까?')) {
//1. 이미지 파일 업로드
const uploadImageUrl = await handleUpload();
//2. 모달창에 입력된 새로운 데이터
const newData = {
email: 'test',
content,
store,
date: new Date(),
title,
image_url: uploadImageUrl
};
setData((prev) => [newData, ...prev]);
//3. 파이어스토어에 데이터 저장
const collectionRef = collection(db, 'newData');
await addDoc(collectionRef, newData);
setModalOpen(false);
} else { return;}
}
catch (Error) {
console.log('Inputform.jsx (form Error): ', Error);
}
}}
>
)
▶ 맨 위에 #해결 부분
끝.