728x90
주요 기능
- 폼 POST 요청
- 폼 입력값 유효성 + 오류 메시지 출력하기
- 아이돌 검색
- 등록 후 list 페이지로 이동
✅api GET으로 있는 아이돌 목록 띄우기
- 페이지사이즈를 크게해서 모든 데이터를 다 불러오기…
// get: 리스트 보여주기
const getIdolsData = async () => {
setLoading(true);
const result = await getIdols({ pageSize: 10000 });
const idolsList = result.list;
// 기존 아이돌 리스트 뒤에 연달아 나와야 함
setIdolsData(idolsList );
};
useEffect(() => {
getIdolsData();
}, []);
🌻폼 채우고 데이터 출력해보기
const handleInputChange = (e) => {
const { name, value } = e.target;
if (name === 'targetDonation') {
const val = e.target.value;
setOutput(val);
setMin(e.target.min || 0);
setMax(e.target.max || 1000000);
}
setDatas((prevDatas) => ({
...prevDatas,
[name]: value,
}));
};
const handleSubmit = (e) => {
e.preventDefault();
console.log(datas);
};
- 폼과 등록 버튼에는 onSubmit={handleSubmit}적용
- 아이돌 아바타에 onClick 프롭 추가 후 해당 클릭한 아이돌 id 값 받아오기
- 각 input에는 onChange={handleInputChange}
<IdolAvatar
src={idol.profilePicture}
size="medium"
value={idol.id}
onClick={() => {
console.log(idol.id);
setDatas((prevDatas) => ({
...prevDatas,
idolId: idol.id,
}));
}}
/>
🌻아이돌 선택하면 체크 표시 해주기
{datas.idolId === idol.id ? (
<CheckedIdolAvatar
src={idol.profilePicture}
size="medium"
value={idol.id}
/>
) : (
<IdolAvatar
src={idol.profilePicture}
size="medium"
value={idol.id}
onClick={() => {
console.log(idol.id);
setDatas((prevDatas) => ({
...prevDatas,
idolId: idol.id,
}));
}}
/>
)}
- 아이돌 아바타 선택하면 해당 아이디가 idolId에 저장된다. → idolId와 idol.id가 같으면 체크표시된 아바타로 선택됨.
✅api POST로 데이터 추가하기
넣어야 할 데이터
{
"deadline": "2024-05-04T02:07:58.087Z", -> 날짜
"targetDonation": 0, -> 필요한 크레딧
"subtitle": "string", -> 내용
"title": "string", -> 제목
"idolId": 0 -> 아이돌 선택하면 해당 id 지정
}
- requestData로 폼 데이터 가져오기
import axiosInstance from '../axiosInstance';
const postDonationsApi = async (requestData) => {
try {
await axiosInstance.post(`/donations`, requestData);
} catch (error) {
throw new Error(error.message);
}
};
export default postDonationsApi;
const handleSubmit = async (e) => {
e.preventDefault();
try {
console.log('폼 데이터:', datas);
await postDonationsApi(datas);
console.log('POST 요청 완료');
} catch (error) {
console.error('요청 에러:', error);
}
};
postDonationsApi(datas) - 폼 데이터 api로 보내기
✅폼 유효성에 따른 버튼 활성화 유무
const handleSubmit = async (e) => {
e.preventDefault();
if (
datas.idolId &&
datas.title &&
datas.subtitle &&
datas.targetDonation &&
datas.deadline
) {
console.log('Form data:', datas);
await postDonationsApi(datas);
} else if (!datas.idolId) {
alert('아이돌은 선택해주세요!');
} else if (!datas.title) {
titleRef.current.focus();
} else if (!datas.subtitle) {
subtitleRef.current.focus();
} else if (!datas.deadline) {
alert('마감일을 설정해주세요!');
} else if (datas.targetDonation === 0) {
alert('크레딧을 설정해주세요!');
}
};
- useRef 써서 비어있으면 focus되도록 설정
- 모든 값이 있어야 등록할 수 있음.
✅폼 유효성 재구현
폼 유효성에 관한 고찰…
const [datas, setDatas] = useState({
idolId: '',
title: '',
subtitle: '',
targetDonation: 0,
deadline: '',
});
// 비어있음 false, 값이 있으면 true
// 초기상태는 모두 false
const isIdolIdValid = !!datas.idolId;
const isTitleValid = !!datas.title;
const isSubtitleValid = !!datas.subtitle;
const isDeadlineValid = !!datas.deadline;
const isTargetDonationValid = datas.targetDonation !== 0;
- 각 데이터 값이 비어있음 false, 값이 있으면 true로 설정하기
- !!: 불리언 값으로 변환해줌.
{isIdolIdValid || (
<p className="ml-2 mt-2 text-[12px] text-red-600">
아이돌을 선택해주세요
</p>
)}
- false면 p 오류태그 뜨게한다.
근데? 위의 방법처럼 하면 초기 페이지에서 바로 오류메시지가 떠버린다.
해결법) 각각 valid값을 state로 저장해서, 처음 렌더링될 때는 true값으로 오류메시지를 안 보이게 하고, 등록할 때 비어있으면 false로 상태 값을 바꿔서 오류메시지를 뜨게해보자..!
const [isIdolIdValid, setIsIdolIdValid] = useState(true);
const [isTitleValid, setIsTitleValid] = useState(true);
const [isSubtitleValid, setIsSubtitleValid] = useState(true);
const [isDeadlineValid, setIsDeadlineValid] = useState(true);
const [isTargetDonationValid, setIsTargetDonationValid] = useState(true);
- 필요한 valid 값을 state로 저장하기.. 초기 상태는 true
useEffect(() => {
setIsIdolIdValid(true);
setIsTitleValid(true);
setIsSubtitleValid(true);
setIsDeadlineValid(true);
setIsTargetDonationValid(true);
}, [datas]);
- 초기 렌더링일 때 valid는 모두 true값으로 오류 메시지 안 보이게
- datas가 실시간으로 바뀌면 오류메시지 안 뜨게
const handleSubmit = async (e) => {
e.preventDefault();
if (
datas.idolId &&
datas.title &&
datas.subtitle &&
datas.targetDonation &&
datas.deadline
) {
await postDonationsApi(datas);
alert('조공 등록이 완료되었습니다!');
navigate('/list');
} else {
if (!datas.idolId) setIsIdolIdValid(false);
if (!datas.title) setIsTitleValid(false);
if (!datas.subtitle) setIsSubtitleValid(false);
if (!datas.targetDonation) setIsDeadlineValid(false);
if (!datas.deadline) setIsTargetDonationValid(false);
}
};
- 등록 버튼을 눌렀을 때 인풋 값이 비어있으면 해당 인풋값 아래에 오류메시지 띄우기
- 다 채워져 있으면 datas POST 요청으로 보내고 list 페이지로 이동
애니메이션 넣기
keyframes: {
vibration: {
from: { transform: 'rotate(0.5deg)' },
to: { transform: 'rotate(-0.5deg)' },
},
},
animation: {
vibration: 'vibration .1s ease-in-out 3'
}
className={`font-regular w-[10rem] rounded-md bg-blackSecondary px-4 py-2 text-sm text-white focus:outline-none ${!isDeadlineValid ? 'animate-vibration border border-red-600' : ''}`}
✅아이돌 검색
const [keyword, setKeyword] = useState('');
const getIdolsData = async () => {
setLoading(true);
const result = await getIdols({ pageSize: 10000, keyword });
const idolsList = result.list;
// 기존 아이돌 리스트 뒤에 연달아 나와야 함
setIdolsData(idolsList);
};
useEffect(() => {
getIdolsData();
}, [keyword]);
const handleKeywordSearch = (e) => {
setKeyword(e.target.value);
};
<input
placeholder="검색할 아이돌 이름 혹은 그룹명을 입력해주세요"
onChange={handleKeywordSearch}
className="border-whiteSecondary-500 font-regular h-[32px] w-full rounded-[3px] border bg-blackSecondary px-9 py-2 focus:outline-none"
/>
- input에서 실시간으로 검색할 때마다 바로 아이돌 아바타가 뜨게 설정.
결과
⚠️cors 이슈
웹 애플리케이션에서 다른 도메인으로 리소스를 요청할 때 발생할 수 있는 보안 정책
- 응답 헤더에 CORS 관련 설정 추가
import axios from 'axios';
const teamName = '6-15';
const axiosConfig = {
baseURL: `https://fandom-k-api.vercel.app/${teamName}`,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
'Access-Control-Allow-Headers':
'Origin, X-Requested-With, Content-Type, Accept',
},
};
const axiosInstance = axios.create(axiosConfig);
export default axiosInstance;
- 모든 origin으로부터의 요청을 허용
- 허용되는 HTTP 메서드 설정
- 허용되는 헤더를 설정
⚠️서드파티 이슈
**Third-party cookie will be blocked. Learn more in the Issues tab.**
제3자 쿠키: 사용자가 방문한 웹사이트가 아닌 다른 웹사이트에서 설치하는 쿠키
이걸 해주면 된다는데 난 이미 되어있음 → 서드파티 쿠키 허용 사이트에 우리 사이트를 넣음
'🔥React 뽀개기' 카테고리의 다른 글
react-hook-form + yup = 회원가입/로그인(feat.쿠키) (0) | 2024.08.02 |
---|---|
input 공통 컴포넌트로 만들기 (feat. react-hook-form + yup) (0) | 2024.08.01 |
스크롤시 투명한 배경에서 배경색 넣기(feat. 화살표 클릭 시 맨 위로 이동하기) (0) | 2024.07.27 |
서버 상태 💞 클라이언트 상태 (0) | 2024.07.20 |
React Query 왜 씀? (1) | 2024.07.20 |