Closed choinamechoi closed 1 year ago
질문에 포함된 코드를 이미지만으로 삽입하면, 답변 과정에서 직접 코드를 모두 쳐야 합니다. 😥 그리고 테스트 할 수 있도록 저장소 URL 또는 프로젝트 파일을 압축해 포함해주셨다면 더 좋았을 거에요.
문제 원인은 getQue 함수에 있습니다. get().then()
비동기 지연 처리와 상관없이
곧 바로 receivedData(빈 배열)을 반환합니다. 그래서 (0)에서 빈 배열이 출력된 것이고,
(2), (4)에서 아이템 원소가 없으므로 모두 undefined
가 출력된 것입니다.
(1)에서 Console에 아이템이 출력된 것은 비동기 요청/응답 과정에서 뒤 늦게 배열에 아이템이 추가되었기 때문입니다.
응답 결과로 데이터가 채워지기 전, 아이템 개수가 0
임을 [[Prototype]]: Array(0)
출력 코드로 알 수 있습니다.
SearchRTDB, getQue, Mypage 코드를 아래와 같이 변경한 후 다시 테스트 해보세요. 직접 테스트 할 수 없었으므로 머리 속에서 시뮬레이션 한 코드이다 보니 오류가 발생할 가능성도 있습니다. 😳
function SearchRTDB(searchKey, searchValue) {
const que = query(dbRef, orderByChild(searchKey), equalTo(searchValue));
// getQue 함수가 반환한 Promise 객체를 다시 반환
return getQue(que);
}
function getQue(que) {
// get(que)는 Promise를 반환
return get(que)
.then((snapshot) => {
const receivedData = [];
snapshot.forEach((childSnapshot) => {
receivedData.push(childSnapshot.val());
});
// resolved 상태인 경우, 데이터가 채워진 receivedData 반환
return receivedData;
})
.catch(error => {
console.error(error.message);
return { message: error.message };
});
}
function Mypage() {
const [data, setData] = useState([]);
// 네트워크 요청/응답과 같은 사이드 이펙트 처리를 위해 useEffect 훅 사용
useEffect(() => {
// SearchRTDB()는 Promise를 반환
SearchRTDB('prkplceNo', '350-4-000008')
// 요청에 따른 응답 결과를 처리
.then((receivedData) => {
// Console 패널에 응답 결과 출력
console.log(receivedData);
// 응답 결과 값으로 data 상태 업데이트
setData(receivedData);
})
}, []);
return (...);
}
와.. 해결이 되었습니다.. 감사합니다. 추가 질문이 있습니다. 이건 그냥 궁금한것이고 실제론 Test1 이라는 배열을 사용 안해도 됩니다.
-상황-
-나름 생각해본것- "비동기 요청/응답 과정에서 뒤 늦게 배열에 아이템이 추가되었기 때문입니다."
이렇게 이해하면 되는건가요? 이런 문제가 앞으로도 많을것 같은데 이건 동기/비동기 부분을 더 공부해보면 되는거겠죠?
혹시 몰라 깃허브주소 남깁니다. : https://github.com/choinamechoi/car-zip/tree/feature/%2363
사용한 함수 위치 : car-zip > src > getDB > ReadDB 사용한 페이지 위치 : car-zip > src > pages >Mypage.jsx
env파일도 추가를 해야되는데 그것은 개인 디스코드 문자로 남기겠습니다. 감사합니다!!
함수 컴포넌트 내부의 Test1 배열이 계속 빈 배열인 이유가 뭘까요?
리액트의 렌더링 과정에 대해 이해하면 문제 원인을 유추할 수 있습니다.
리액트 함수 컴포넌트 내부는 렌더링 될 때 마다 초기화 됩니다. Test1은 일반 자바스크립트 지역 변수이니, 리액트에 의해 렌더링 될 때 마다 초기 값인 빈 배열로 설정됩니다. 그러므로 "Test1은 항상 빈 배열"인 것입니다.
반면 리액트에 의해 관리되는 상태(state) 또는 기억된 데이터(memoized data)의 경우 리액트에 의해 렌더링 되더라도 이전 값을 기억합니다.
확인을 위해 아래 코드를 복사 붙여넣기 하여 결과를 테스트 해보세요.
// [자바스크립트] 함수 내, 지역 변수
const Test1 = [];
// [리액트] 기억된 데이터 관리 (useRef 훅: 반환 객체의 current 속성을 수정해도 리-렌더링 안 됨)
const Test1Ref = useRef([]);
// [리액트] 상태 관리 (useState 훅: setData 함수가 실행되면 리-렌더링 됨)
const [data, setData] = useState([]);
// [리액트] 이펙트 관리 (useEffect 훅: 종속성 배열이 빈 경우, 1회만 렌더링 됨)
useEffect(() => {
SearchRTDB('prkplceNo', '350-4-000008').then((receivedData) => {
// [자바스크립트] 지역 변수 값 업데이트
Test1.push(...receivedData);
// [리액트] 기억된 데이터 업데이트 (리-렌더링 안 됨)
Test1Ref.current.push(...receivedData);
// [리액트] 상태 업데이트 (리-렌더링 됨)
setData(receivedData);
});
}, []);
// ✅ 리-렌더링 될 때, Test1은 빈 배열로 초기화 됨
console.log('Test1:', Test1);
console.log('Test1.length:', Test1.length);
// ✅ 리-렌더링 될 때, Test1Ref 객체는 초기화 안 됨 (리액트에 의해 기억 됨)
// Test1Ref.current에 기억된 배열 데이터 아이템이 추가 됨
console.log('Test1Ref.current:', Test1Ref.current);
console.log('Test1Ref.current.length:', Test1Ref.current.length);
결과는 아래 스크린샷과 같습니다. 😃
답변 내용 중 "상태 업데이트", "이펙트 콜백" 레이블이 포함된 글을 참고해 읽고 이해해보세요. 😉
질문 작성자
최영범
문제 상황
원하는 최종 목표 :
문제점 :
구체적인 설명 :
SearchRTDB라는 함수에 파라미터를 넘겨줘서 서버(파이어베이스 realtime db)에서 저 파라미터에 해당하는 데이터를 뽑아오는 알고리즘을 구성했습니다.
1번째 사진을 보면 데이터를 뽑아와서 TEST 변수에 넣어주었고 , 데이터가 잘 뽑혔는지 확인을 위한 콘솔 로그를 찍었습니다.
2번째 사진에 보면 알 수 있듯 TEST 변수 자체는 array로 찍혀서 TEST[0]을 통해 데이터를 콘솔로그에 찍어보려 했으나 undefined가 나왔습니다.
혹시나 하여 TEST의 타입을 찍어보니 object가 나와서 데이터가 basicCharge 라는 key를 가지고 있어 .basicCharge를 작성하여 콘솔 찍어보았으나 undefined가 나왔습니다.
getQue ,SearchRTDB 함수에 async, awiat 을 이용하여 비동기 처리했을때에는 array로 잘 동작을 한걸로 보아 타이밍 관련 문제도 관련있을것같습니다..
async,await,then을 사용하지 않은 이유는 그 범위 밖에서 데이터를 사용을 하려다보니 콜백문제가 생겨 사용을 안하고있습니다.
혹시 getQue 함수 안에서 데이터를 .then 안에서 받아서 이런 문제가 생긴걸까요?
또 async,await 사용을 피하고싶은 이유가 리액트 함수 컴포넌트 안에서 사용 하려면 그 함수 자체를 또 async로 감싸줘야되는데 그렇게 되면 그 함수컴포넌트가 promise를 반환한다면서 컴포넌트를 사용못하게 되는 에러가 나서 사용을 못하고있습니다.
프로젝트 저장소 URL
node_modules
폴더를 제외한 나머지를 압축해 이 곳에 첨부하세요.환경 정보