내일배움캠프

230712 리액트 같은 src 경로 이미지 리로드하기 (presigned url 업로드 미리보기 시 )

Neda 2023. 7. 12. 20:50

230712 리액트 같은 src 경로 이미지 리로드하기

presigned url을 통해 이미지를 업로드하면 미리 지정해 둔 버킷과 키를 사용하여 업로드가 된다. 이미지를 업로드할 때 버킷의 파일 경로를 사용해 미리 보기를 표시하는데, 파일을 변경해도 브라우저에서 이미지를 캐싱하기 때문에 다시 리로드 시키지 않는다.

 

원인은 브라우저의 이미지 자동 캐싱

awsImageUrl 경로에 있는 파일이 변경해도 브라우저는 변경 여부를 알 수 없기 때문에 캐싱한채로 리액트에서 리렌더링 되어도 다시 불러오지 않는다. 따라서 캐싱을 무시하고 같은 경로의 이미지를 다시 불러올 수 있는 방법을 찾아야 한다.

<img width={500} src={awsImageUrl}/>

 

이미지 경로에 현재 시간을 이용하기

src에 있는 값을 변경하면 다른 경로로 인식하여 다시 불러오게 되는데,

이 값을 현재 시간으로 주면 항상 src가 바뀌기 때문에 계속 리로드 된다.

리로드 된다는 목적은 달성했지만,

"항상" 리로드 되기 때문에 리액트 컴포넌트 특성 상 다른 요소로 인해 리렌더링이 일어나면 계속 불러오게 되고,

아래 사진에 보듯이 글 작성을 위해 텍스트를 입력하면 리렌더링이 일어나고,

그 때마다  같은 파일을 계속 불러와서 낭비가 심해진다.

<img width={500} src={imageUrl+'?'+ new Date().getTime()}/>

 

이미지 경로에 count 값 이용하기

단순히 파일을 업로드할 때마다 count 숫자 값을 증가시키는 것으로 중복해서 불러오는 문제를 해결 할 수 있었다.

이제는 리렌더링이 되더라도 파일 업로드를 통해 count 값이 바뀌지 않는 한 캐싱된 원래 이미지를 사용한다.

...
const [count,setCount] = useState(0)
const [isLoading,setLoading] = useState(false)
const [imageUrl,setImageUrl] = useState('')
const [uploadUrl,setUploadUrl] = useState('')

const handleSubmitUploadImage = async (event) => {
  const file = event.target.files[0]
  if(!file) return
  setLoading(true)
  let res
  if(!uploadUrl) {
    res = await getUploadURL(file.name)
    setImageUrl("https://react-level4-images.s3.ap-northeast-2.amazonaws.com/"+res.key)
    setUploadUrl(res.url)
  }
  await uploadImageS3(uploadUrl || res.url,file)
  setCount(prev=>prev+1)
  setLoading(false)
}
return(
...
<img width={500} src={imageUrl+'?'+count}/>
...
)