[ TIL 221208 ] SWR 공식문서

ponyo·2022년 12월 8일
0

Today I Learned

목록 보기
20/30

SWR

데이터 가져오기를 위한 React Hooks

SWR 홈페이지

"SWR"이라는 이름은 HTTP RFC 5861에 의해 알려진 HTTP 캐시 무효 전략인 stale-while-revalidate에서 유래되었습니다. SWR은 먼저 캐시(스태일)로부터 데이터를 반환한 후, fetch 요청(재검증)을 하고, 최종적으로 최신화된 데이터를 가져오는 전략입니다.

시작하기

설치

yarn add swr

#or npm

npm install swr

빠른 시작

JSON 데이터를 사용하는 일반적인 RESTful API라면 먼저 네이티브 fetch의 단순한 래퍼인 fetcher 함수를 생성해야 합니다.

const fetcher = (...args) => fetch(...args).then(res => res.json())

그 다음, useSWR을 임포트하고 함수 컴포넌트 내에서 사용하여 시작하면 됩니다.

import useSWR from 'swr'

function Profile () {
  const { data, error } = useSWR('/api/user/123', fetcher)

  if (error) return <div>failed to load</div>
  if (!data) return <div>loading...</div>

  // 데이터 렌더링
  return <div>hello {data.name}!</div>
}

일반적으로, 세 가지 요청 상태가 가능합니다: "loading", "ready", "error". data와 error 값을 사용해 현재 요청의 상태를 알아내고, 해당하는 UI를 반환할 수 있습니다.

재사용 가능하게 만들기

웹 앱을 구축할 때, UI의 많은 곳에서 데이터를 재사용할 필요가 있을 것입니다. SWR 위에서는 재사용 가능한 데이터 hook을 만드는 것이 믿을 수 없을 정도로 쉽습니다.

function useUser (id) {
  const { data, error } = useSWR(`/api/user/${id}`, fetcher)

  return {
    user: data,
    isLoading: !error && !data,
    isError: error
  }
}

이 패턴을 적용함으로써 명령형 방식으로 데이터를 가져오는 것에 대해 잊을 수 있습니다: 요청을 시작, 로딩 상태를 업데이트, 최종 결과를 반환. 대신, 코드는 더 선언적입니다: 컴포넌트에서 사용되는 데이터가 무엇인지만 명시하면 됩니다.

예시

실제 예시로, 저희 웹 사이트는 모두 user에 의존하는 navbar와 그 콘텐츠를 보여줍니다.

전통적으로는 최상위 레벨 컴포넌트에서 useEffect를 사용해 데이터를 한 번 가져오고, 이를 props를 통해 자식 컴포넌트에 전달합니다(현재는 에러 상태를 처리하지 않습니다)

// 페이지 컴포넌트

function Page () {
  const [user, setUser] = useState(null)

  // 데이터 가져오기
  useEffect(() => {
    fetch('/api/user')
      .then(res => res.json())
      .then(data => setUser(data))
  }, [])

  // 전역 로딩 상태
  if (!user) return <Spinner/>

  return <div>
    <Navbar user={user} />
    <Content user={user} />
  </div>
}

// 자식 컴포넌트

function Navbar ({ user }) {
  return <div>
    ...
    <Avatar user={user} />
  </div>
}

function Content ({ user }) {
  return <h1>Welcome back, {user.name}</h1>
}

function Avatar ({ user }) {
  return <img src={user.avatar} alt={user.name} />
}

보통 최상위 레벨 컴포넌트에서 가져온 모든 데이터를 유지하고 트리 아래의 모든 자식 컴포넌트의 props로 추가해야 합니다. 페이지에 더 많은 데이터 의존성을 추가한다면 코드는 점점 유지하기가 힘들어집니다.

Context를 사용하여 props 전달을 피할 수 있습니다만 동적 콘텐츠 문제가 여전히 존재합니다: 페이지 콘텐츠 내 컴포넌트들은 동적일 수 있으며, 최상위 레벨 컴포넌트는 그 자식 컴포넌트가 필요로하는 데이터가 무엇인지 알 수 없을 수도 있습니다.

SWR은 이 문제를 완벽하게 해결합니다. 우리가 막 생성한 useUser hook을 사용해 다음과 같이 리팩토링할 수 있습니다.

// 페이지 컴포넌트

function Page () {
  return <div>
    <Navbar />
    <Content />
  </div>
}

// 자식 컴포넌트

function Navbar () {
  return <div>
    ...
    <Avatar />
  </div>
}

function Content () {
  const { user, isLoading } = useUser()
  if (isLoading) return <Spinner />
  return <h1>Welcome back, {user.name}</h1>
}

function Avatar () {
  const { user, isLoading } = useUser()
  if (isLoading) return <Spinner />
  return <img src={user.avatar} alt={user.name} />
}

데이터는 이제 데이터가 필요한 컴포넌트로 범위가 제한되었으며 모든 컴포넌트는 서로에게 독립적입니다. 모든 부모 컴포넌트들은 데이터나 데이터 전달에 관련된 것들을 알 필요가 없습니다. 그냥 렌더링할 뿐입니다. 코드는 이제 유지하기에 더 간단하고 쉽습니다.

가장 아름다운 것은 이들이 동일한 SWR 키를 사용하며 그 요청이 자동으로 중복 제거, 캐시, 공유되므로, 단 한 번의 요청만 API로 전송된다는 것입니다.

또한, 애플리케이션은 이제 사용자 포커스나 네트워크 재연결 시에 데이터를 갱신할 수 있습니다! 이는 사용자의 노트북이 슬립으로부터 깨어나거나 브라우저 탭을 전환할 때 자동으로 데이터가 갱신된다는 것을 의미합니다.

실제 사용 시 게시물 업데이트 예정 🚀

profile
😁

0개의 댓글