[TIL] 07/05 :: 포켓몬 2.

yeseul·2024년 7월 4일

<TIL>

목록 보기
32/43

* Image 컴포넌트

  • src , width , height , alt 는 필수 속성이다.
  • src 속성(props)에 정적 이미지가 아닌 인터넷상의 이미지도 지정할 수 있다.
    • 인터넷상의 이미지를 사용할 때는 무조건 width, height 속성을 입력해야 한다.
    • 왜냐하면 정적 이미지일 경우 Next.js가 build 할 때 width, height 속성을 계산할 수 있으나 원격 이미지(인터넷상의 이미지) 일 경우 width, height 속성을 계산하지 못하기 때문이다.
      -> Next 자체에서 이미지 크기에 맞는 최적화를 진행한다.
import Image from 'next/image'
 
export default function Page() {
  return (
    <div>
      <Image
        src="/profile.png"
        width={500}
        height={500}
        alt="Picture of the author"
      />
    </div>
  )
}

✔️ vercel 배포시 고려해야할 점

  • 이미지 컴포넌트는 비용이랑 관련이 있기 때문에 보안이 필요하다.

  • 버셀에 배포시, 이미지 컴포넌트 사용은 비싼 서비스이다.

  • Image 컴포넌트만 사용시 외부 이미지 사용에 대한 error 가 발생한다.

  • remotePatterns 적용하기

    • 외부 이미지를 Image 컴포넌트의 src에 적용하려면 보안상의 이유(비용문제발생)로 개발자가 어떤 url 의 외부 이미지들을 허용할 것인지 명시해줘야 한다.
/** @type {import('next').NextConfig} */
const nextConfig = {
  images: {
    remotePatterns: [
      {
        protocol: "https",
        hostname: "picsum.photos",
        pathname: "/50/50",
      },
    ],
  },
};

export default nextConfig;

  • domains 로 지정해줘도 되긴하는데, 콘솔에 경고창이 뜨더라!! 웬만해선 remotePatterns 를 쓰는걸로!
  • next.config 파일을 수정했기 때문에 서버를 껐다가 다시 켜야 된다.
  • 포켓몬 리스트를 불러올때 아래와 같은 priority 경고창이 생겼다.

✔️priority

: Next.js 에서 제공하는 이미지 최적화 관련 기능중 하나.

  • 중요한 이미지를 우선적으로 로드하도록 설정할 수 있다.
  • 랜딩 페이지에서 제일 처음 보이는 이미지에는 이 속성을 지정하는 게 유리하다.
    • 이 속성은 Boolean 타입이기 때문에 priority라고 적으면 true가 되고, 안 적으면 false가 된다.
    • 물론 이미지에 lazy 로딩을 적용했을 때 priority 속성을 적용하면 lazy 로딩은 무시된다.
import Image from 'next/image'

export default function MyComponent() {
  return (
    <div>
      <Image
        src="/path/to/image.jpg"
        alt="설명"
        width={500}
        height={500}
        priority
      />
    </div>
  )
}

* Lazy loading

: Next.js에서의 Lazy Loading은 페이지 로딩 시 모든 콘텐츠를 한 번에 로드하지 않고, 사용자가 실제로 필요로 할 때 콘텐츠를 로드하는 기술.
-> 이를 통해 초기 로딩 시간을 단축하고 사용자 경험을 개선할 수 있다.

✔️ next/image 컴포넌트는 이미지에 대한 Lazy Loading을 기본적으로 지원한다.

import Image from 'next/image'

export default function MyComponent() {
  return (
    <div>
      <Image
        src="/path/to/image.jpg"
        alt="설명"
        width={500}
        height={500}
        loading="lazy"
      />
    </div>
  )
}
  • next/image를 사용할 때 loading 속성을 lazy로 설정하면 이미지를 Lazy Loading 방식으로 로드할 수 있다.
  • 이미지는 사용자가 실제로 스크롤하여 해당 이미지가 화면에 나타날 때 로드된다.
  • 한 화면에 딱 보여주는정도까지만 데이터 가져와서 보여주고 스크롤 내릴때 또 보여준다.
    ex) 순서를 정해주고 배너 먼저 가져와서 보여주는..

* 환경변수 처리

  • 프로젝트 root 에 .env.local 파일 만든 후 api key 나 url 작성
  • 서버 환경(node)에서 환경변수 접근 시에는 자유롭게 환경변수 네이밍 가능
// .env
DB_HOST=https://db-host.com
  • 클라이언트 환경(browser)에서 환경변수 접근 시에는 prefix로 NEXT_PUBLIC_ 을 붙여준다.
NEXT_PUBLIC_MY_HOST=http://localhost:3000
  • url 입력한곳에 환경변수 사용
 const response = await axios.get(
      `${process.env.NEXT_PUBLIC_MY_HOST}/api/pokemons/${id}`
    );

✔️ vercel 배포시 환경변수 등록

  • Redeploy 실행

  • 탭에서 Logs 로 로그도 확인할 수 있는 점 알아두기!



* QueryClient + useState

✔️ useState 사용없이 매번 queryClient 생성


-> 컴포넌트가 다시 렌더링될 때마다 new QueryClient()가 호출되어 새로운 queryClient 객체가 생성된다.

✔️ useState 훅을 사용하여 QueryClient 인스턴스를 생성하고 상태로 관리하면,

-> QueryClient 인스턴스가 컴포넌트가 리렌더링 될때마다 새로 생성되지 않도록 할 수 있다.
-> 또한, 참조 동일성을 유지하며, React Query와 React가 예상하는 상태 관리를 조절하고, 컴포넌트 렌더링과 상태 업데이트를 조절하기 위함이다.

  1. 초기 렌더링 중 설정 :
    React Query는 초기 렌더링 동안에 QueryClient를 설정하고 사용하기 위한 상태를 필요로 한다.
    초기 렌더링 동안에만 실행되는 함수를 제공하면 Lazy 초기 상태(Lazy initial state)를 활용해 초기 렌더링 동안에만 QueryClient를 생성하고, 이후에는 참조 동일성을 유지한다. 이것은 초기 설정을 효율적으로 관리하는 방법 중 하나다.

  2. 동적 설정 관리 :
    QueryClientProvider의 설정을 동적으로 변경해야 할 때, useState를 활용해 QueryClient를 상태로 관리하는 것이 유용하다.
    동적으로 설정을 변경하려면 상태를 업데이트하고 그 변경을 QueryClientProvider에 적용하면 된다.

  3. 컴포넌트 렌더링과 분리 :
    QueryClientProvider의 설정을 컴포넌트 수명주기와 연관해서 관리하고자 할 때 useState를 사용할 수 있다.
    이렇게 하면 컴포넌트가 마운트되거나 언마운트될 때 설정을 업데이트하고 관리할 수 있다.

  • useState의 초기값으로 함수 (() => new QueryClient()) 를 전달하여 초기화 시점에만 QueryClient 인스턴스를 생성하도록 한다.
    이 함수는 한번만 호출된다.

  • 이후에는 참조 동일성을 유지하게 된다.

    • 컴포넌트가 리렌더링될 때에도 초기화 함수는 다시 호출되지 않으며, 처음 생성된 queryClient 객체가 유지된다.
      -> 불필요한 queryClient 객체 생성을 피할 수 있고, 성능 최적화에 도움이 된다.
  • defaultOptions를 통해 기본 설정을 지정

  • staleTime: 1000 * 60 * 5는 쿼리 데이터가 5분 동안 신선하게 유지된다는 것을 의미한다.
    즉, 5분 동안 동일한 데이터를 재사용하고, 그 이후에만 다시 fetch를 시도


💭 useMemo 로 최적화 시키는 것은 어떨지?

  • useMemo는 dependency가 변경되는 경우에만 값을 재계산하고, queryClient에는 dependency가 없으니, 가능하지 않을까?
function MyApp({ Component, pageProps }) {
  const [queryClient] = React.useMemo(() => new QueryClient(),[]);

  return (
    <QueryClientProvider client={queryClient}>

-> useMemo를 사용해도 똑같은 효과를 가져오지만 useMemo는 그 목적이 좀 다르다.
useMemo에 대한 공식문서의 일부분을 살펴보자.

"만들기" 함수와 종속성 배열을 전달합니다. useMemo종속성 중 하나가 변경된 경우에만 메모된 값을 다시 계산합니다. 이 최적화는 모든 렌더링에서 비용이 많이 드는 계산을 피하는 데 도움이 됩니다.

useMemo 의미론적 보증이 아닌 성능 최적화 \에 의존할 수 있습니다. 미래에 React는 이전에 메모한 일부 값을 "잊고" 다음 렌더링에서 다시 계산하도록 선택할 수 있습니다(예: 오프스크린 구성 요소를 위한 메모리 확보). useMemo 없이도 계속 작동하도록 코드를 작성한 다음, 추가하여 성능을 최적화하십시오.

  • 오프스크린 구성 요소란?
    오프스크린 구성 요소는 화면에 렌더링되지 않지만, 나중에 필요할 수 있는 구성 요소를 의미한다. ex) 탭으로 숨겨진 내용이나, 사용자가 특정 조건에서만 볼 수 있는 내용

-> 💡 useMemo는 참조동일성(의미론적 보증)보다는 성능개선을 위한 목적이 크다.

  • 기존에 useMemo 없이도 동작하는 코드를 useMemo를 이용하여, 성능최적화를 하는 것이다. 그러므로 참조동일성을 위한 useState를 사용한다.

-> 💡 queryClient가 변경될 가능성이 있다.

  • 동적 설정 변경: queryClient의 설정 옵션(예: defaultOptions, queryCache 등)이 애플리케이션 실행 중에 변경될 수 있다.
  • useMemo를 사용하면 queryClient가 변경되더라도 컴포넌트가 재렌더링되지 않을 수 있기 때문에 queryClient가 변경될 가능성이 있다면 useState를 사용하여 queryClient를 관리하는 것이 더 안전할 수 있다.
  • useMemo는 상태를 변경하는 기능을 제공하지 않으며, 단지 메모이제이션된 값을 반환한다.

0개의 댓글