admin의 구조는
AdminForm > Title + AdminBox > RequestContainerBox 2개 > 컨테이너 css 구조 ...
로 되어있다. 따라서 2개의 컨테이너를 나눠서 무한스크롤을 적용하려면 각각 useRef로 bottom 을 지정해주어야 한다. 그렇게 하려면 RequestContainerBox 컴포넌트 내부에 접근해야 하는데,AdminBox에서 forwardRef 를 사용하여 하위 컴포넌트에 ref를 적용했다.
const Data1 = data1?.pages.flatMap((x) => x.data.response);
const DataArr1 = Data1 || [];
<RequestContainerBox
border=" 2px solid #F5F6FA;"
title="정보 수정 요청"
data={DataArr1}
route={routes.basicInfoEditRequest}
modi={true}
isLoading={isLoading1}
error={error1}
ref={bottomObserver1} //✅
isError={isError1}
></RequestContainerBox>
const RequestContainerBox = React.forwardRef( ✅
({ title, border, data, route, modi, isLoading, error, isError }, ref) => {
return (
<RequestContainerBoxCss>
<TitleBox
title={title}
isLoading={isLoading}
error={error}
isError={isError}
/>
<RequestContain
border={border}
datas={data}
route={route}
modi={modi}
isLoading={isLoading}
error={error}
>
{!isLoading && <Bottom ref={ref}>. </Bottom>} ❌
</RequestContain>
</RequestContainerBoxCss>
);
}
);
RequestContainerBox.displayName = "RequestContainerBox"; ✅ ❌
✅ 가 forwardRef 를 사용한 부분이다.
❌ 아래는 사용하는데 생긴 두개의 에러사항을 해결한 것이다.
forwardRef 를 사용 도중
error Component definition is missing display name react/display-name
위와 같은 eslint 에러가 났다.
const hello = function()
{
console.log("Hello");
};
이와 같은 함수를 익명함수 라고 하는데, 익명함수는 크롬 브라우저에서 디버깅 한 결과를 보면 이름이 나오지 않게 된다.
forwardRef() 함수를 호출할 때 익명 함수를 넘기게 되면 브라우저에서 디버깅 시 함수의 이름을 알 수 없게 되고, 에러가 날 수 있는 위험이 있다.
다음은 forwardRef 를 사용할 때 함수 이름이 나올 수 있게 하는 방법이다.
1️⃣ forwardRef() 함수에 익명 함수를 대신에 이름이 있는 함수 넘기기.
const RequestContainerBox = forwardRef(function Input(props, ref) {
return <RequestContainerBox type="text" ref={ref} />;
});
2️⃣ forwardRef() 함수의 호출 결과로 기존 컴포넌트를 대체.
function RequestContainerBox(props, ref) {
return <input type="text" ref={ref} />;
}
RequestContainerBox = forwardRef(RequestContainerBox);
3️⃣ displayName 으로 컴포넌트에 이름 설정하기
const RequestContainerBox = forwardRef((props, ref) => {
return <input type="text" ref={ref} />;
});
RequestContainerBox.displayName = "RequestContainerBox";
첫 화면에서는 로더가 이렇게 잘 출력이 되는데, 다음 페이지 호출할 때는 로더가 생기지 않았다.
tenstack공식페이지 에 있는 무한스크롤 예제에서 다음 페이지를 호출할때 fetching 상태가 됐다. 그래서 코드를 아래로 수정했더니 로더가 잘 출력되었다.
{(isLoading || isFetching) && <Loader></Loader>}
그러면 왜 다음페이지를 요청할때만 fetcing 상태가 될까?
isLoading은 서버에 데이터 요청을 처음 할 때
isFetching은 서버에 데이터 요청을 다시 할 때 (캐시된 데이터가 있을 때)
라고 한다.
자세히 말하자면 isLoading = isFetching + 쿼리에 캐시된 데이터가 없을때
라서 isLoading은 처음 데이터를 요청할때 쓰이고, isFetching은 서버에 요청을 다시 할 때 사용한다고 한다.
그러면 내가 작성한 코드를 예로 들자면 첫 요청 시 로딩 상태이며, 데이터들을 가져온다. 다음 페이지를 요청할때는 앞에 데이터를 요청했었기 때문에 캐시된 데이터가 존재하며, 그 데이터는 디폴트 설정을 안해줬기 때문에 바로 stale 한 상태가 된다. 그리고 캐시된 데이터가 있는상태에서 요청했기 때문에 패칭 상태가 된다.
리액트 쿼리의 장점 중 하나가 캐싱을 이용할 수 있다는 점인데 캐싱을 하나도 이용을 안하고 있다는걸 깨달았다.. 추후에 리팩토링으로 캐싱된 데이터를 이용하는 방법과 초기설정에 대해 공부해봐야겠다.
레퍼런스
forwardRef
https://ko.legacy.reactjs.org/docs/forwarding-refs.html
displayName
https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/display-name.md
isLoading vs isFetching
https://velog.io/@himprover/React-query-%EC%97%90%EC%84%9C-isLoading%EC%9D%B4%EB%9E%91-isFetching%EC%9D%80-%EB%AD%90%EA%B0%80-%EB%8B%A4%EB%A5%B4%EC%A7%80