Back to Nextra

Getting Started

examples/swr-site/content/en/docs/getting-started.mdx

2.0.0-beta.67.6 KB
Original Source

import { Link } from 'nextra-theme-docs' import { Callout, FileTree, Steps } from 'nextra/components'

export const metadata = { sidebarTitle: ( <> <i>Getting</i> <s>Started</s> </> ) }

Getting Started

https://google.com/da;djaldhksagfugsufgasuyfgyuasgfuasgdjasbdjasdjkasfuydfasyrdyafsdygasjdgasgdsafgdhjfasgjdfsahjdfsahjgdasgdjkasgdkjasgdkjasgdkagdkjasgdkjagdkjagdkagdkagdkjagdkagdkagdkagda

  • foo
    • bar
    • baz
      • qux
      • qwe
        1. he
        2. be
          1. wo
          2. be da
            • da
            • ba
<details> <summary>**111** 111</summary> content line 1 some more content <details> <summary>**222** 222</summary> content line 2 some more content <details> <summary>**333** 333</summary> content line 3 some more content </details> </details> </details> <Steps> ## Step 1 <Steps> ### Step 1.1
### Step 1.2
</Steps> ## Step 2 <Steps> ### Step 2.1
### Step 2.2
</Steps> </Steps>

Development

<Steps> ### Install Dependencies

Run pnpm install in the project root directory.

Lint

<Steps> #### Lint ESLint
run `pnpm lint`

#### Lint Prettier

run `pnpm lint:prettier --write` to format the entire project.
</Steps>

Test

Run pnpm test

</Steps>
css
html {
  background: red;
}
graphql
type Character {
  name: String
}
python
# type Character {
class Character:
  # name: String
  def name(self):
    return self._name
csharp
// type Character {
public class Character {
  // name: String
  public String Name { get; }
}

__esModule

Docs theme box-decoration-theme: clone can create confusing output over line breaks


<Link href="https://google.com">Link</Link>

export const myVar = '"I am from export const"'

Foo {myVar}

Bar code

Latex $latex^2$

<strong>Da</strong>
MaChi<s>na</s>

export const Test = props => <b>{props.someProp}</b>

Qux <Test someProp="someVal" />

My file is <MyFile />{:js}
math
x^2
math
\int_1^2x^2

Inside your React project directory, run the following:

sh
npm i swr __esModule

Quick Start $latex$

For normal RESTful APIs with JSON data, first you need to create a fetcher function, which is just a wrapper of the native fetch:

jsx
const fetcher = (...args) => fetch(...args).then(res => res.json())
<Callout> If you want to use GraphQL API or libs like Axios, you can create your own fetcher function. Check [here](/docs/data-fetching) for more examples. </Callout> <FileTree> <FileTree.Folder name="users-service" defaultOpen> <FileTree.File name="schema.graphql" /> </FileTree.Folder> <FileTree.Folder name="posts-service" defaultOpen> <FileTree.File name="schema.graphql" /> </FileTree.Folder> </FileTree> <FileTree> <FileTree.Folder name="users-service" defaultOpen> <FileTree.File name="schema.graphql" /> <FileTree.Folder name="posts-service" defaultOpen> <FileTree.File name="schema.graphql" /> </FileTree.Folder> </FileTree.Folder> </FileTree> <details> <summary>Renders properly</summary> <div className="flex justify-center">content</div> </details> <details> <summary>Renders on next line</summary> <div className="flex justify-center">content</div> </details>

Then you can import useSWR and start using it inside any function components:

jsx
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>

  // render data
  return <div>hello {data.name}!</div>
}

Normally, there're 3 possible states of a request: "loading", "ready", or "error". You can use the value of data and error to determine the current state of the request, and return the corresponding UI.

Make It Reusable

Here's a JavaScript expression: const a = 1 + 2{:js}.

When building a web app, you might need to reuse the data in many places of the UI. It is incredibly easy to create reusable data hooks on top of SWR:

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

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

And use it in your components:

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

  if (isLoading) return <Spinner />
  if (isError) return <Error />
  return 
}

By adopting this pattern, you can forget about fetching data in the imperative way: start the request, update the loading state, and return the final result. Instead, your code is more declarative: you just need to specify what data is used by the component.

Example

In a real-world example, our website shows a navbar and the content, both depend on user:

import { WelcomeImage } from '@app/_icons'

<WelcomeImage className="mt-6 dark:invert" />

Traditionally, we fetch data once using useEffect in the top level component, and pass it to child components via props (notice that we don't handle error state for now):

jsx
// page component

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

  // fetch data
  useEffect(() => {
    fetch('/api/user')
      .then(res => res.json())
      .then(data => setUser(data))
  }, [])

  // global loading state
  if (!user) return <Spinner />

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

// child components

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

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

function Avatar({ user }) {
  return 
}

Usually, we need to keep all the data fetching in the top level component and add props to every component deep down the tree. The code will become harder to maintain if we add more data dependency to the page.

Although we can avoid passing props using Context, there's still the dynamic content problem: components inside the page content can be dynamic, and the top level component might not know what data will be needed by its child components.

SWR solves the problem perfectly. With the useUser hook we just created, the code can be refactored to:

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

// child components
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 
}

Data is now bound to the components which need the data, and all components are independent to each other. All the parent components don't need to know anything about the data or passing data around. They just render. The code is much simpler and easier to maintain now.

The most beautiful thing is that there will be only 1 request sent to the API, because they use the same SWR key and the request is deduped, cached and shared automatically.

Also, the application now has the ability to refetch the data on user focus or network reconnect! That means, when the user's laptop wakes from sleep or they switch between browser tabs, the data will be refreshed automatically.