Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: 식품 이미지(SuspendedImg)에 lazy loading 적용 #529

Merged
merged 5 commits into from
Oct 22, 2023

Conversation

n0eyes
Copy link
Collaborator

@n0eyes n0eyes commented Oct 21, 2023

📄 Summary

  • 식품 이미지에 빠져있던 lazy 속성 추가
  • SuspendImg의 lazy loading 기능을 LazyImg를 활용하여 구현
  • LazyImg가 callbackRef를 받을 수 있도록 보강
  • 이미지 중복 다운로드 방지

🙋🏻 More

img.src = src!;
}),
...(staleTime == null ? {} : { staleTime }),
...(cacheTime == null ? {} : { cacheTime }),
enabled: enabled && Boolean(src),
enabled: lazy ? isIntersected : true,
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lazy loading의 경우 돔이 감지되었을 때 이미지 요청을 하도록 변경(버그 수정)하였습니다

interface SuspendedImgProps extends ComponentPropsWithoutRef<'img'> {
staleTime?: number;
cacheTime?: number;
enabled?: boolean;
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

유용할 것 같지 않은 속성을 제거하였습니다

};

export default SuspendedImg;
export default memo(SuspendedImg);
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

memo를 적용했습니다

@@ -13,7 +13,7 @@ const FoodItem = (foodItemProps: FoodItemProps) => {
return (
<FoodItemWrapper to={`pet-food/${id}`}>
<FoodImageWrapper>
<FoodImage src={imageUrl} alt="Food image" />
<FoodImage src={imageUrl} alt="Food image" lazy />
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

누락됐던 lazy 속성을 추가했습니다

@@ -8,7 +8,7 @@ interface UseIntersectionObserverOptions<T extends HTMLElement> {
export const useIntersectionObserver = <T extends HTMLElement>(
options?: UseIntersectionObserverOptions<T>,
) => {
const localRef = useRef<T>(null);
const localRef: MutableRefObject<T | null> = useRef<T>(null);
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ref.current 수정이 필요하여 MutableRefObject로 타입을 지정하였습니다

Comment on lines +22 to +24
if (isIntersected && targetRef.current && !targetRef.current.src && src) {
targetRef.current.src = src;
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

!targetRef.current.src: 이미지 중복 다운을 방지(이미지 다운 실패 시)하기 위하여 추가한 조건입니다
src: src 속성에 올바르지 않은 경로(ex. undefined)가 추가되는 것을 방지하기 위하여 추가한 조건입니다

Comment on lines +13 to +20
const callbackRef = useCallback((instance: HTMLImageElement | null) => {
targetRef.current = instance;

if (!ref) return;

// eslint-disable-next-line no-param-reassign
typeof ref === 'function' ? ref(instance) : (ref.current = instance);
}, []);
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

외부 ref와 내부 ref(targetRef)에 동일한 돔을 할당하고자 img 엘리먼트에 callbackRef를 삽입하는 방식으로 변경하였습니다.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

더 자세히 설명해주실수잇나요??

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LazyImg는 외부에서 ref를 주입받을 수 있는데요!

내부적으로는 lazy loading을 위해 useIntersectionObserver에서 반환된 targetRef를 사용하고 있어요! (옵저빙 되고 있는 ref)

외부 ref를 신경쓰지 않을 땐 targetRef를 img 엘리먼트에 바로 주입해도 문제가 없었지만 외부 ref가 주입될 수 있는 경우
ref는 콜백 함수 혹은 refObject일 수 있습니다!

각 경우의 수에 대비하고 외부 ref에 img 엘리먼트를 제공함과 동시에 targetRef에도 ref와 동일한 img 엘리먼트를 할당하기 위해 커밋 페이즈에 돔과 함께 실행되는 callbackRef 방식을 사용하여 각 ref에 동일한 img 엘리먼트를 할당하였습니다!

});

const callbackRef = useCallback((instance: HTMLImageElement | null) => {
targetRef.current = instance;
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

targetRef를 통해 img 엘리먼트에 접근하고 이미지 다운로드를 조작합니다

if (!ref) return;

// eslint-disable-next-line no-param-reassign
typeof ref === 'function' ? ref(instance) : (ref.current = instance);
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

외부 ref가 callbackRef인 경우 그대로 실행시키고, 아닌 경우 외부 ref에 img 엘리먼트를 할당합니다

HyeryongChoi
HyeryongChoi previously approved these changes Oct 22, 2023
Copy link
Collaborator

@HyeryongChoi HyeryongChoi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

고생하셧슴다 질문 코멘트 하나 달았어요!

Copy link
Member

@ksone02 ksone02 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

고생했어요~

@n0eyes n0eyes merged commit 727dbcc into develop Oct 22, 2023
1 check passed
@n0eyes n0eyes deleted the refactor/#528 branch October 22, 2023 10:23
@n0eyes n0eyes changed the title refactor: 식품 이미지 미처 적용 안됐던 lazy loading 적용 refactor: 식품 이미지(SuspendedImg) 미처 적용 안됐던 lazy loading 적용 Nov 21, 2023
@n0eyes n0eyes changed the title refactor: 식품 이미지(SuspendedImg) 미처 적용 안됐던 lazy loading 적용 refactor: 식품 이미지(SuspendedImg)에 lazy loading 적용 Nov 21, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

[FE] 식품 이미지 lazy loading 적용
3 participants