![article thumbnail image](https://blog.kakaocdn.net/dn/cJ3xcH/btsLQ3QrKt8/kizOlKGtuYvFJYZS9RqIdk/img.png)
해결하기 전 코드
// 지점 데이터 페이징 처리
const pageingBranchs = async () => {
try {
const token = localStorage.getItem('accessToken');
// 지점 데이터 가져오는 함수 호출 (토큰 필요)
await getBranchs(token);
} catch (error) {
// 403 == 토큰 만료
if (error.response && error.response.status === 403) {
try {
const newToken = await refreshAccessToken();
await getBranchs(newToken);
} catch (error) {
// 새 토큰 요청도 실패하면 인증 만료 알림 및 로그아웃 처리
alert("인증이 만료되었습니다. 다시 로그인 해주세요.");
handleAdminLogout();
}
} else {
console.error('There was an error fetching the branchs pageing!', error);
}
}
};
// 지점 데이터 가져오기
const getBranchs = async (token) => {
const params = {
pageSize, // 페이지 크기
pageNumber, // 현재 페이지 번호
};
// 검색 조건이 있다면
if (searchName && searchName.trim() !== '') {
// 검색어(지점명)를 params에 추가
params.branchName = searchName;
}
try {
const response = await axios.get(${process.env.REACT_APP_API_URL}/arentcar/manager/branchs/paged, {
params,
headers: {
Authorization: Bearer ${token},
},
withCredentials: true,
});
if (response.data && response.data.length === 0) {
setBranchs([]);
setPageNumber(1);
return;
} else {
setBranchs(response.data); // 응답이 있다면 지점 데이터 상태에 저장
getTotalCount(); // 검색 결과에 맞는 총 개수 다시 가져오기
}
} catch (error) {
console.error('Error fetching branches:', error);
}
};
// 전체 지점 수 가져오기
const getTotalCount = async () => {
try {
const token = localStorage.getItem('accessToken');
// 총 개수를 가져오는 함수 호출, await를 이용하여 API 요청 끝날때까지 대기 후 코드 실행
await getCount(token);
} catch (error) {
if (error.response && error.response.status === 403) {
try {
const newToken = await refreshAccessToken();
await getCount(newToken);
} catch (error) {
alert("인증이 만료되었습니다. 다시 로그인 해주세요.");
handleAdminLogout();
}
} else {
console.error('There was an error fetching the branchs count!', error);
}
}
};
useEffect(() => {
if (branchs.length === 0 && searchName.trim() !== '') {
alert("존재하지 않는 지점명입니다. 다시 입력해주세요.");
}
}, [branchs]); // branchs 상태가 빈 배열로 변경될 때만 alert
해결 된 코드
// 지점 데이터 페이징 처리
const pageingBranchs = async () => {
try {
const token = localStorage.getItem('accessToken');
// 지점 데이터 가져오는 함수 호출 (토큰 필요)
await getBranchs(token);
} catch (error) {
// 403 == 토큰 만료
if (error.response && error.response.status === 403) {
try {
const newToken = await refreshAccessToken();
await getBranchs(newToken);
} catch (error) {
// 새 토큰 요청도 실패하면 인증 만료 알림 및 로그아웃 처리
alert("인증이 만료되었습니다. 다시 로그인 해주세요.");
handleAdminLogout();
}
} else {
console.error('There was an error fetching the branchs pageing!', error);
}
}
};
// 지점 데이터 가져오기
const getBranchs = async (token) => {
const params = {
pageSize, // 페이지 크기
pageNumber, // 현재 페이지 번호
};
// 검색 조건이 있다면
if (searchName && searchName.trim() !== '') {
// 검색어(지점명)를 params에 추가
params.branchName = searchName;
}
try {
const response = await axios.get(`${process.env.REACT_APP_API_URL}/arentcar/manager/branchs/paged`, {
params,
headers: {
Authorization: `Bearer ${token}`,
},
withCredentials: true,
});
if (response.data && response.data.length === 0) {
// if (branchs.length !== 0) {
// setBranchs([]); // 상태가 이미 빈 배열이면 업데이트하지 않음
// }
setPageNumber(1);
return;
} else {
setBranchs(response.data); // 응답이 있다면 지점 데이터 상태에 저장
getTotalCount(); // 검색 결과에 맞는 총 개수 다시 가져오기
}
} catch (error) {
console.error('Error fetching branches:', error);
}
};
// 전체 지점 수 가져오기
const getTotalCount = async () => {
try {
const token = localStorage.getItem('accessToken');
// 총 개수를 가져오는 함수 호출, await를 이용하여 API 요청 끝날때까지 대기 후 코드 실행
await getCount(token);
} catch (error) {
if (error.response && error.response.status === 403) {
try {
const newToken = await refreshAccessToken();
await getCount(newToken);
} catch (error) {
alert("인증이 만료되었습니다. 다시 로그인 해주세요.");
handleAdminLogout();
}
} else {
console.error('There was an error fetching the branchs count!', error);
}
}
};
useEffect(() => {
console.log("useEffect 실행: branchs.length =", branchs.length);
// 상태가 빈 배열이 되고, 검색어가 있는 경우에만 alert 실행
if (branchs.length === 0 && searchName.trim() !== '') {
setTimeout(() => {
alert("존재하지 않는 지점명입니다. 다시 입력해주세요.");
}, 0); // 비동기적으로 alert 호출
}
}, [branchs]); // branchs 상태 변경 감지
// 총 지점 수 요청
const getCount = async (token) => {
// 검색어(searchName)이 있다면 params에 추가
const params = searchName ? { branchName: searchName } : {};
try {
// API 요청: 지점 수 가져오기
const response = await axios.get(`${process.env.REACT_APP_API_URL}/arentcar/manager/branchs/count`,
{
params,
headers: {
Authorization: `Bearer ${token}`
},
withCredentials: true,
});
if (typeof response.data === 'number') {
setTotalCount(response.data);
}
} catch (error) {
console.error('총 지점 수를 가져오는데 실패했습니다:', error);
}
};
// 페이지 번호 / 크기가 바뀔 때 데이터 요청
useEffect(() => {
pageingBranchs(); // 지점 데이터 가져오기
getTotalCount(); // 전체 지점 수 가져오기
}, [pageNumber, pageSize]); // 페이지 번호, 크기가 변경될 때 실행
원인
1. React를 사용해 검색 기능을 구현하는 과정에서 검색어가 존재하지 않을 경우 alert를 띄우도록 코드를 작성했음
하지만 특정 조건에서 alert가 두 번 중복으로 호출되는 문제가 발생
- `setBranchs([])`로 상태를 업데이트한 후 `useEffect`가 실행
if (response.data && response.data.length === 0) {
setBranchs([]);
setPageNumber(1);
return;
}
useEffect(() => {
if (branchs.length === 0 && searchName.trim() !== '') {
alert("존재하지 않는 지점명입니다. 다시 입력해주세요.");
}
}, [branchs]);
- 이때, `branchs.length === 0` 조건이 만족되면 `alert`가 호출됨
- 만약 `setBranchs([])`로 상태를 업데이트하기 전에 branchs가 이미 빈 배열이라면, 상태는 변하지 않았지만 `useEffect`가 여전히 실행될 가능성이 있음
- 즉, API 응답에서 상태 변경이 일어나지 않아도 useEffect가 재실행 됨
해결 방법
1. useEffect에서 alert 중복 호출 방지
- alert를 비동기 처리로 변경하여 상태 업데이트가 완료된 후 한 번만 호출되도록 제어.
- 브라우저의 비동기 함수인 `setTimeout`을 사용하여 `alert` 호출을 비동기로 지연.
useEffect(() => {
if (branchs.length === 0 && searchName.trim() !== '') {
setTimeout(() => {
alert("존재하지 않는 지점명입니다. 다시 입력해주세요.");
}, 0); // setTimeout을 사용해 alert 호출을 이벤트 큐에 넣어서 비동기로 처리
}
}, [branchs]);
2.중복 상태 업데이트 방지
- `getBranchs` 함수 내부에서 상태를 변경하기 전에 현재 상태를 확인하고, 중복 업데이트 방지
if (response.data && response.data.length === 0) {
if (branchs.length !== 0) {
setBranchs([]); // 상태가 이미 빈 배열이면 업데이트하지 않음
} // 빈 배열이 아니라면 페이지 넘버를 1로 설정하고 반환
setPageNumber(1);
return;
}
3. 디버깅으로 원인 확인
useEffect(() => {
console.log("useEffect 실행: branchs.length =", branchs.length);
if (branchs.length === 0 && searchName.trim() !== '') {
setTimeout(() => {
alert("존재하지 않는 지점명입니다. 다시 입력해주세요.");
}, 0);
}
}, [branchs]);
결과
- alert가 정확히 한 번만 호출되도록 수정.
- 상태 업데이트 중 중복 실행을 방지하여 불필요한 useEffect 호출을 차단함
'Problem Solving' 카테고리의 다른 글
[ArentCar][PS] setBranchs 주석 처리해도 새 지점 반영되는 문제 - 해결 (0) | 2024.12.16 |
---|---|
[ArentCar][PS] 쉼표 연산자로 인한 useState 초기값 설정 오류 문제 - 해결 (0) | 2024.12.13 |
[Git][PS] push to origin has encountered a problem 오류 해결 (0) | 2024.09.23 |
[PS][React] Route를 이용했을 때 github pages의 404 에러 해결 (a 태그 -> link to) (0) | 2024.08.01 |
[PS][React] react-scripts 은(는) 내부 또는 외부 명령 실행할 수 있는 프로그램 또는 배치 파일이 아닙니다 (0) | 2024.07.20 |