Closed jellyjoji closed 1 year ago
지난 번 알려드렸던 실수를 다시 반복하지 않는 개발자가 되길 바랍니다. 🥹
먼저 문제가 해결된 결과를 영상으로 확인하세요. https://github.com/FRONTENDSCHOOL6/ready-act/assets/74365275/abe430a5-513a-43ee-9f09-7ce64614b1aa
지난 번에도 알려드렸듯이 로컬 스토리지에서 데이터를 읽어오는 것은 비동기 처리가 필요합니다. 그러므로 useState 훅을 사용해 지연된 처리가 필요하다는 점 이번엔 꼭 기억해주세요!
idData
가 서버로부터 응답받은 결과로 업데이트가 되면 실행되는 이펙트 함수를 설정하고, 조건에 따라 creator
필드 값을 설정하도록 작성합니다. 아래 작성된 코드의 주석을 참고하세요.
Creator.jsx
function Creator() {
// ...
// localStorage에서 아이디 정보를 가져오는 함수
const [localStorageId] = useState(
() => JSON.parse(localStorage.getItem('pocketbase_auth')).model.id
);
const [idData, setIdData] = useState({});
// idData 상태가 업데이트 되면 실행되는 이펙트 콜백 함수
useEffect(() => {
if (idData.id) {
// idData 값이 서버로부터 가져와 업데이트 되면
// creator 폼 필드를 { id, name } 객체 값으로 설정합니다.
updateCreateRoomForm('creator', { id: idData.id, name: idData.name });
}
}, [idData]);
// ...
return (
<>
<div
readOnly
label="생성자"
placeholder="생성자"
labelClassName="creator"
inputClassName="w-full defaultInput"
>
{idData.name}
</div>
</>
);
}
“방 만들기” 할 때 서버에 전송되는 creator
필드 값은 creatorValue.id
여야 합니다. 관계된 users 콜렉션의 레코드 ID가 저장되어야 하기 때문입니다.
CreateRoom.jsx
const handleCreate = async (e) => {
e.preventDefault();
// ...
const creatorValue = createRoomForm.creator;
const data = new FormData();
// ...
// creator 객체의 id 값을 'creator'로 설정
data.append('creator', creatorValue.id);
// ...
};
Creator.jsx
import { AppContext } from '@/App';
import FormInput from '../../components/FormInput';
import { useContext, useState, useEffect } from 'react';
import { useParams } from 'react-router-dom';
import { pb } from '@/api/pocketbase';
import { ClientResponseError } from 'pocketbase';
function Creator() {
const { updateCreateRoomForm } = useContext(AppContext);
const [productIdData, setProductIdData] = useState("");
const { id } = useParams();
// localStorage에서 아이디 정보를 가져오는 함수
// 로컬 스토리지에서 데이터를 읽어오는 것은 비동기 처리가 필요합니다. 그러므로 useState 훅을 사용해 지연된 처리가 필요
const [localStorageId] = useState(() => JSON.parse(localStorage.getItem('pocketbase_auth')).model.id);
const [idData, setIdData] = useState({});
// idData 상태가 업데이트 되면 실행되는 이펙트 콜백 함수
useEffect(() => {
if (idData.id) {
// idData 값이 서버로부터 가져와 업데이트 되면
// creator 폼 필드를 { id, name } 객체 값으로 설정합니다.
updateCreateRoomForm('creator', { id: idData.id, name: idData.name });
}
}, [idData])
useEffect(() => {
async function readUserId() {
try {
// 포켓 호스트에서 아이디 정보를 가져오는 함수
const pocketHostId = await pb.collection('users').getFullList();
// localStorageId 과 pocketHostId 두개를 비교하여 일치하는것만 setIdData 에 주입하여 렌더
pocketHostId.filter((idList) => {
if (idList.id === localStorageId) {
setIdData(idList);
}
})
}
catch (error) {
if (!(error instanceof ClientResponseError)) {
console.error(error);
}
}
}
async function readProductId() {
try {
const productId = await pb.collection('products').getFullList({
expand: 'creator',
filter: `creator.id="${localStorageId}"`,
});
setProductIdData(productId);
} catch (error) {
if (!(error instanceof ClientResponseError)) {
console.error(error);
}
}
}
readUserId();
readProductId()
}, [])
// 이제 이 비교된 결과값을 넣는 Creator input 창이 필요
// creator input 의 값을 context api 에서 뽑아서 사용 app context form 에 넣어서 상태 관리
return (
<>
<FormInput readOnly value={idData.name || ''} label="생성자" type="text" name="creator" placeholder="생성자 정보" inputClassName="w-full defaultInput" />
</>
)
}
export default Creator;
CreateRoom.jsx
import { AppContext } from '@/App';
import { pb } from '@/api/pocketbase';
import Button from '@/components/Button';
import FormInput from '@/components/FormInput';
import CreateHeader from '@/layout/CreateHeader';
import CategoryDropdown from '@/parts/create/CategoryDropdown';
import ContentTextarea from '@/parts/create/ContentTextarea';
import DatePicker from '@/parts/create/DatePicker';
import FileUpload from '@/parts/create/FileUpload';
import MeetingPoint from '@/parts/create/MeetingPoint';
import ParticipateCounter from '@/parts/create/ParticipateCounter';
import PaymentToggleButton from '@/parts/create/PaymentToggleButton';
import Status from '@/parts/create/Status';
import { ClientResponseError } from 'pocketbase';
import { useContext, useRef, useState } from 'react';
import { Helmet } from 'react-helmet-async';
import Creator from '@/parts/create/Creator';
function CreateRoom() {
const { createRoomForm, updateCreateRoomForm } = useContext(AppContext);
const formRef = useRef(null);
const categoryRef = useRef(null);
const titleRef = useRef(null);
const contentRef = useRef(null);
const priceRef = useRef(null);
const dateRef = useRef(null);
const paymentRef = useRef(null);
const ParticipateCounterRef = useRef(null);
const uploadImageRef = useRef(null);
const statusRef = useRef(null);
const handleCreate = async (e) => {
e.preventDefault();
const categoryValue = categoryRef.current.value;
const titleValue = titleRef.current.value;
const contentValue = contentRef.current.value;
const priceValue = priceRef.current.value;
const dateValue = dateRef.current.value;
const paymentValue = paymentRef.current.dataset.payment;
const ParticipateCounterValue = Number(
ParticipateCounterRef.current.textContent
);
const meetingPointValue = createRoomForm.meetingPoint;
const creatorValue = createRoomForm.creator.id;
const uploadImageValue = uploadImageRef.current.files[0];
const statusValue = statusRef.current.value;
const data = new FormData();
data.append('category', categoryValue);
data.append('title', titleValue);
data.append('content', contentValue);
data.append('price', priceValue);
data.append('pickup', dateValue);
data.append('payment', paymentValue);
data.append('participateNumber', ParticipateCounterValue);
data.append('meetingPoint', meetingPointValue);
data.append('creator', creatorValue);
data.append('participate', creatorValue);
if (uploadImageValue) {
data.append('uploadImage', uploadImageValue);
}
data.append("status", statusValue);
for (const [key, value] of data.entries()) {
console.log(key, value);
}
// return
try {
await pb.collection('products').create(data);
// navigate('/products');
} catch (error) {
if (!(error instanceof ClientResponseError)) {
console.error(error);
}
}
}
return (
<>
<Helmet>
<title>방만들기</title>
</Helmet>
<div >
<CreateHeader />
<form
encType="multipart/form-data"
ref={formRef}
onSubmit={handleCreate}
>
<div className="flex flex-col gap-4 p-4 relative"
>
<CategoryDropdown
ref={categoryRef}
title="카테고리"
className="w-full defaultInput"
/>
<FormInput
ref={titleRef}
type="text"
placeholder="상품명을 입력해주세요."
labelClassName="product name"
inputClassName="defaultInput w-full"
label="상품명"
/>
<FormInput
ref={priceRef}
type="number"
placeholder="0원"
labelClassName="product price"
inputClassName="defaultInput w-full"
label="상품 가격"
/>
<ContentTextarea
ref={contentRef}
title="내용"
placeholder="공구 모임 주요내용을 알려주세요."
className="w-full defaultInput"
labelClassName="product content"
/>
<DatePicker
ref={dateRef}
title="픽업 날짜"
className="w-full defaultInput"
labelClassName="date Picker"
/>
<Status
ref={statusRef}
title="상태"
className="w-full defaultInput "
labelClassName="status"
/>
<Creator />
<PaymentToggleButton
ref={paymentRef}
title="정산 방법"
labelClassName="payment"
/>
<ParticipateCounter ref={ParticipateCounterRef} title="인원" />
<MeetingPoint title="만날 장소" />
<FileUpload
ref={uploadImageRef}
title="파일 업로드"
className="bg-[#EBF8E8] p-4 rounded-lg text-primary-500"
/>
</div>
<div className="bg-white fixed bottom-0 max-w-xl w-full p-4 drop-shadow-2xl">
<Button type="submit" className="activeButton lgFontButton w-full ">
방 만들기
</Button>
</div>
</form>
</div>
</>
);
}
export default CreateRoom;
내용
form data 에서 Creator 생성자 정보를 불러와서 표기해주려고 합니다.
Creator.jsx
※ 댓글에 이슈 해결 완료 후 결과 또는 해결 과정 이미지 첨부