#09 No-code 之旅 — 怎麽在 Client-side 抓取资料?SWR 简介

安安!前几天讲了怎麽在专案里用些 data fetching functions 做 pre-rendering。不过如果想要直接在 client-side 抓取资料呢?有什麽方法?~ 今天跟大家分享一个 data fetching (抓取资料) 的 library,SWR

SWR

什麽是 SWR

SWRstale-while-revalidate 的简称,意思是我们抓取资料的时候,会先拿到 cache 里 (stale / 旧资料) 的,然後在背後去发请求抓取资料 (revalidate),再回传最新的资料。SWR 是一个提供抓取资料功能的 react hooks library,没错,他是 react hooks!

为什麽要用 SWR

在 client-side 抓取资料算简单,可是也必须注意一些事情,例如重复呼叫某 API。有了 SWR 之後,我们不用再担心这件事!SWR 帮我们做这些:

  • 可重复使用的 react hooks
  • 管理 cache
  • 避免重复发 API 请求
  • 定时抓取资料,让体验很像 real-time (即时)
  • 遇到错误时,重试发请求
  • 支援 SSG,ISR,SSR
  • 支援 TypeScript

Setup

很简单~ 在专案的目录下,输入以下指令:

yarn add swr
# or
npm install swr

装完就可以这样使用:

import useSWR from 'swr'

function User() {
  // Github API: https://api.github.com/users/vercel
  const { data, error } = useSWR('https://api.github.com/users/vercel', fetcher)

  if (error) return <div>发生错误 :o</div>
  if (!data) return <div>loading...</div>
  return <div>Hi {data.name}!</div> // Hi Vercel!
}

这里 useSWR hooks 接收两个 parameters,keyfetcher function。

  • keySWR 会根据这 key 做 cache,通常是请求的 API URL

  • fetcher:去做抓取的 function,这 function 接收 key 当 parameter 然後回传 data (资料)。可以用一般的 fetchaxios,或是 GraphQL,只要可以用 key 去抓取和回传资料都可以

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

做成 Reusable Custom Hooks

上面那段 code 只能抓取 vercel 这 Github user 的资料,如果我们想抓其他人的资料呢?要复制贴上吗?不用~ 我们可以做 React custom hook:

function useUser (id) {
  const { data, error } = useSWR(`https://api.github.com/users/${id}`, fetcher)

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

然後在 React component 里使用:

// Avatar component
function Avatar ({ id }) {
  const { user, isLoading, isError } = useUser(id)

  if (isLoading) return <Spinner />
  if (isError) return <Error />
  return <img src={user.avatar_url} alt={user.name} />
}

那如果有不只一个 component 需要用到 user 的资料呢?useUser hook 可以在很多 component 里重复使用喔:

// Info component
function Info ({ id }) {
  const { user, isLoading } = useUser(id)
  if (isLoading) return <Spinner />
  if (isError) return <Error />
  return <h1>Welcome back, {user.name} (@{user.login})</h1>
}

是不是很方便!而且 SWR 会自动做 cache 还有避免重复发请求,虽然我们使用了 useUser 两次,可是实际上我们只发一次 API request 喔!这麽做可以减少 props 传递的动作,每个独立的 component 自己处理资料~

同步资料?

服务器端或是资料库里的资料有可能会变,我们该怎麽拿到最新值?该怎麽跟服务器做同步?SWR 的 revalidation 机制成为答案!有几个 revalidate 时机:

  • focus 时 (revalidateOnFocus):这里的 focus 是指 浏览器 tab 的 focus,使用者有没有正在看该 tab,如果没有,每次使用者回到这 tab,SWR 会做 revalidate (重新抓取资料),让使用者看到最新的资料
  • interval (refreshInterval):定时去做 revalidate,只要画面上有用到这些资料,SWR 会根据我们设定的 interval 去做资料更新,让画面看起来有即时更新
  • reconnect 时 (revalidateOnReconnect):使用者有可能会断线,例如电脑进入睡眠模式,当使用者重新连到网路时,SWR 会做 revalidate 更新资料~
  • 永远不同步 (useSWRImmutable):以上三种 revalidate 时机会让资料保持同次的状态,可是如果资料完全不会变,那何必 revalidate 呢?我们可以把 revalidate 机制关掉,让 SWR 永远不做资料同步,只抓一次资料!

Next.jsSWR

看起来都很棒,想要开始用在 Next.js 的专案里,该怎麽用呢?

Client-side Data Fetching

其实如果想要在浏览器端去抓取资料的话,直接用 useSWR 在 component 里就可以~ 就像上面的 code 一样,基本上就是在 React components 里面使用 useSWR 或是 custom SWR hooks 喔!

Pre-rendering

可是 Next.js 又可以做 pre-rendering,例如 SSG 或是 SSR,那还是可以用 SWR 吗?当然可以的!SWR 是处理 client-side 的资料抓取方式,我们只要可以在 build time 时拿到资料让页面不完全是空的,然後 request time 时在浏览器再重新抓取最新资料。之前如果用 getStaticProps 或是 getServerSideProps 时,我们都会把 props 传到 page (页面) component 里。可是用 SWR 的方式比较不一样:

// 一样在 getStaticProps 抓取资料
export async function getStaticProps () {
  const article = await getArticleFromAPI()
  // 要回传 fallback 的资料!
  return {
    props: {
      fallback: {
        // 这 key 要跟 useSWR 用的 key 一样喔~
        '/api/article': article
      }
    }
  }
}

// Article component
function Article() {
  // 因为 fallback 有包含 `/api/article` 这 key,
  // data 预设值会是 fallback 里设定的值
  // 当使用者在浏览器看到这画面时,SWR 会抓取最新料
  const { data } = useSWR('/api/article', fetcher)
  return <h1>{data.title}</h1>
}

// Page component 收到 getStaticProps 回传的 props.fallback
export default function Page({ fallback }) {
  // SWRConfig 去做设定,在这里设定 fallback 值
  return (
    <SWRConfig value={{ fallback }}>
      <Article />
    </SWRConfig>
  )
}

所以产生页面时会先塞资料进 HTML 档案,不过当使用者在浏览器看到这画面时,SWR 会抓取最新料,更新 HTML 里原本的内容。

小结

如果大家对於 client-side data fetching 有兴趣或需求,真的可以去看看 SWR!简单又方便,还能做 cache,也不用做 props drilling,实在很开心~ 不过我目前也没有在大专案用过 SWR,所以不太清楚会不会不适用在较复杂的专案Q

祝大家周末愉快!

晚安 <3

看更多


<<:  [D09] OpenCV 应用范围

>>:  [30天 Vue学好学满 DAY24] Vue Router-3

CNN
杂谈    

Day 28. F2E-过渡动画

系列文接近尾声,专案最後要来做一个过渡动画效果 我们要做的效果是向左/右滑入滑出,效果可以参考 V...

25. Redux 的用途 & 入门实作 (上)

Redux Redux 跟 React 并没有关系。你可以用 React、Angular、Ember...

Leetcode: 26. Remove Duplicates from Sorted Array

看大家都写leetcode o3o       Input 传入一个已排序好的阵列位置,把它变成se...

D27 - 如何用 Apps Script 自动化地创造与客制 Google Sheet?(四)蒐集大量试算表中的回应

今天的目标: 要怎麽样依照范本复制并改动 Google Sheet,并一次性地的将结果搜集到同一份 ...

Day25 测试写起乃 - spring-command-rspec

在反覆执行 rspec 时会一直需要载入环境,这时候可以透过 spring 帮助你更快的执行 rsp...