Next/image onError처리

8/17/2022

작성자 : 홍원배

 
블로그 v2 프로젝트는 Next 프레임워크를 사용하여 서버에서 렌더링해서 클라이언트로 넘겨주는 pre-rendering 방식을 주로 사용하고 있다.
이 때, nextjs/image의 onError 이벤트처리를 하게 될 경우 배포환경에서 다음과 같은 에러를 만나게 된다.
 
onError이미지가 로드 되지 못하며 반복 실행된다
onError이미지가 로드 되지 못하며 반복 실행된다
 
자세히 다시 한번 오류를 살펴보자
 
notion image
400클라이언트 오류로서 쿼리 마지막 부분을 보면 url이 비어져 있다. next/image에서 이미지가 로드 되지 않을 때(onError 이벤트 발생) 콜백 함수(handleError)가 실행되게 했는데 함수가 설정한 주소를 받아올 수 없는 것이다
import Image from 'next/image' export default function 아무개컴포넌트({something}) { .. .. function handleError(e){ //=> 귀여운 곰돌이 이미지 주소 e.currentTarget.src = 'http://t1.daumcdn.net/friends/prod/editor/dc8b3d02-a15a-4afa-a88b-989cf2a50476.jpg' } .. return ( <Image src={something} onError={handleError} ... /> ) }
 

Why ?

프로젝트의 렌더링 방식을 생각해보며 이론적으로 유추해보자.
  1. SSG(static site generator)는 pre-rendering 방식으로 빌드타임때, onError 이벤트가 붙은 <Image /> 컴포넌트를 포함하여 vercel 서버에서 미리 화면을 렌더링해서 클라이언트로 전해주게 된다.
  1. 이 때 src에 포함되어야 하는 이미지 경로는 외부 API 호출에 대한 응답이다.
    1. (현재 프로젝트에서는 api를 호출하여 이미지 주소값을 받아 src 속성에 바인딩 되게 되는데, api 오류가 나면 “”를 돌려주게 되어있다)
  1. 클라이언트에서 전달을 받아보니 Image src=””라는 falsy한 값을 받게 된다.
  1. onErorr가 발생한다
  1. (중요) 하지만 onError을 처리할 currentTarget이 없다.
    1. currentTarget은 이벤트핸들러가 붙은 DOM을 의미한다
       
currentTarget이 null인 것을 볼 수 있다
currentTarget이 null인 것을 볼 수 있다
 
서버에서 렌더링 화면을 만들어서 클라이언트로 넘겨주기 때문에, 에러가 발생한 이벤트 DOM에 대한 제어권이 달라진 것이 아닐까 추측한다.
추측한 내용이 맞았다면 위 이미지에서 보이듯이 target값이 img 요소로 잡히지만 이것 역시도 에러를 인식을 못할 것이다.
 
 
추측을 가정하에 e.target으로 변경해보았지만,
역시 hydration에 실패
역시 hydration에 실패
 
 
추상적이고 유추가 섞인 내용이지만 포인트는 서버에서 이벤트 에러가 일어난 DOM을 클라이언트가 인식하지 못한다는 것이다. 그렇다면 클라이언트에서 이미지가 로드되지 않으면 onError처리를 해주는 일련의 과정을 전담하여 처리하면 되지 않을까?
 
import Img from "next/image"; import { useEffect, useRef, useState } from "react"; export default function Image({ src, alt = "포스트 썸네일", ...rests }) { const [imgSrc, setImgSrc] = useState(src); function handleError() { const fallbackSrc = "http://t1.daumcdn.net/friends/prod/editor/dc8b3d02-a15a-4afa-a88b-989cf2a50476.jpg"; setImgSrc(fallbackSrc); } useEffect(() => { setImgSrc(src); }, [src]); return <Img src={imgSrc} onError={handleError} {...rests} />; }
에러처리를 클라이언트에서..!
 
useEffect를 통해 컴포넌트가 렌더링 된 후에 다시 한번 src 속성 값을 부여하게 되고 클라이언트에서 onError 이벤트를 유도하게 적용했다.
 
 

결과

 
notion image
실제로 이미지들이 잘 도착하는 것을 확인할 수 있다.
 
 

다른 해결책

무게에만 초점을 맞추면 문제를 풀 수 없습니다. 핵심을 봐야 돼요. - 우영우
 
우영우 변호사의 말처럼, 이 문제는 onError 이벤트핸들러를 회피함으로서 오류시 다른 이미지를 띄운다는 본래의 목적을 간단히 달성할 수 있다.
 
봄날의 햇살 같은 해결책
봄날의 햇살 같은 해결책
 
하지만 CSR, SSR 등의 렌더링 방식의 근본적인 원리와 구조를 이해해야 다른 해결책의 이면에 있는 동작방식도 쉽게 이해하고 성장할 수 있다는 것을 잊지말자
 
    태그 :