GithubHelp home page GithubHelp logo

vercel / swr Goto Github PK

View Code? Open in Web Editor NEW
29.4K 218.0 1.2K 3.47 MB

React Hooks for Data Fetching

Home Page: https://swr.vercel.app

License: MIT License

JavaScript 0.77% TypeScript 99.21% Shell 0.02%
react hook data-fetching swr suspense react-native fetch vercel stale-while-revalidate hooks

swr's Introduction

SWR


Introduction

SWR is a React Hooks library for data fetching.

The name “SWR” is derived from stale-while-revalidate, a cache invalidation strategy popularized by HTTP RFC 5861. SWR first returns the data from cache (stale), then sends the request (revalidate), and finally comes with the up-to-date data again.

With just one hook, you can significantly simplify the data fetching logic in your project. And it also covered in all aspects of speed, correctness, and stability to help you build better experiences:

  • Fast, lightweight and reusable data fetching
  • Transport and protocol agnostic
  • Built-in cache and request deduplication
  • Real-time experience
  • Revalidation on focus
  • Revalidation on network recovery
  • Polling
  • Pagination and scroll position recovery
  • SSR and SSG
  • Local mutation (Optimistic UI)
  • Built-in smart error retry
  • TypeScript
  • React Suspense
  • React Native

...and a lot more.

With SWR, components will get a stream of data updates constantly and automatically. Thus, the UI will be always fast and reactive.


View full documentation and examples on swr.vercel.app.


Quick Start

import useSWR from 'swr'

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

  if (error) return <div>failed to load</div>
  if (isLoading) return <div>loading...</div>
  return <div>hello {data.name}!</div>
}

In this example, the React Hook useSWR accepts a key and a fetcher function. The key is a unique identifier of the request, normally the URL of the API. And the fetcher accepts key as its parameter and returns the data asynchronously.

useSWR also returns 3 values: data, isLoading and error. When the request (fetcher) is not yet finished, data will be undefined and isLoading will be true. When we get a response, it sets data and error based on the result of fetcher, isLoading to false and rerenders the component.

Note that fetcher can be any asynchronous function, you can use your favourite data-fetching library to handle that part.


View full documentation and examples on swr.vercel.app.


Authors

This library is created by the team behind Next.js, with contributions from our community:

Contributors

Thanks to Ryan Chen for providing the awesome swr npm package name!


License

The MIT License.

swr's People

Contributors

agadzik avatar anc95 avatar andrewnt219 avatar anirudh1713 avatar anothertempore avatar clentfort avatar cryptiklemur avatar darrenjennings avatar dependabot[bot] avatar dominictwlee avatar huozhi avatar jason89521 avatar kerumen avatar koba04 avatar matamatanot avatar moonball avatar morgs32 avatar oosawy avatar pa-rang avatar pacocoursey avatar promer94 avatar ramyareye avatar sergiodxa avatar shuding avatar styfle avatar svish avatar takahirohimi avatar teinett avatar vercel-release-bot avatar yesmeck avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

swr's Issues

Cannot use NextJS router query param

When I use NextJS router query param the data fetched from SWR seemed to "randomly" be undefined. But when I change to

const id = typeof window !== 'undefined' ? window.location.pathname.split('/')[2] : ''

instead of

const router = useRouter()
const { id } = router.query

The problem just goes away! Any idea why this is happening?

This is the link to my repo https://github.com/programming-in-th/programming.in.th
The fetching is located in /src/pages/tasks/[id].tsx

PS. I see that example doesn't use query param either but use window.location.pathname slicing instead.

Allow mocking and typing

swr looks really cool 👍

I played around with something similar for request-registry recently.

What I miss in swr over request-registry is the ability to define typings, dependencies and to mock
I would love to know what you think about those features.

Define typings once per endpoint

In request registry you define endpoints e.g.:

import { createGetEndpoint } from "request-registry";
 
// Define a service endpoint to load user information
const userEndpoint = createGetEndpoint<{id: string}, {name: string, age: number}>({
    url: keys => `http://example.com/user/${keys.id}`
});

Then you can use them from a hook e.g.

import {useGetEndPointSuspendable} from 'request-registry-react';

const UserDetails = props => {
    const { name } = useGetEndPointSuspendable(userEndpoint, { id: props.id });
    return <div>{name}</div>;
};

It also works without suspense similar to the swr api:

const UserDetails = props => {
    const endpointState = useGetEndPoint(userEndpoint, { id: props.id });
    if (!endpointState.hasData) {
        return <div>Loading...</div>;
    }
    const { name } = endpointState.value;
    return <div>{name}</div>;
};

This allows autocomplete and type checking for endpointState.value without writing additional endpoint specific types inside the UserDetails component.

Dependencies

Endpoints can also cause mutations e.g.:

import { createPostEndpoint } from "request-registry";
 
// Define a mutation endpoint
const mutateUser = createPostEndpoint<{id: string}, {name: string}, {}>({
    url: keys => `http://example.com/user/${keys.id}`
    // Invalidate all userEndpoint endpoints (similar to your trigger broadcast)
    afterSuccess: () => userEndpoint.refresh()
});

// now for example inside an eventHandler 
  <button onClick={async () => {
      const newName = data.name.toUpperCase()
      // update user 4 and rerender all components which rely on user 4 data:
      await mutateUser(newName)
    }}>

Mocking

For unit tests and storybook we sometimes want to tryout specific scenarios and want to mock backend responses.

// Define your mock data for getUserName
// Typescript will tell you if the mock data doesn't match the types for
// getUserName
const userJoeMock = createMockEndpoint(getUserName, async () => ({
    name: 'Joe',
}));

Now in any unit test or story you can activate the mock:

// Activate mock:
userJoeMock.activate();
// Deactivate mock:
userJoeMock.clear();

There are more utils around this but maybe this is enough to get the basic idea.

I would love to know what you think about those features. :)

Why object instead of array as return value?

The return value of the React state hook is an array, used as:

const [state, setState] = React.useState(false);

This way you could use any name for the state and the setter.

In useSWR is an object:

const { data, error } = useSWR(URL, fetch)

Is there a special reason why it's not an array to? Even one of the examples in the website needs to rename data.

const { data: user } = useSWR('/api/user')
const { data: projects } = useSWR(
  () => '/api/projects?uid=' + user.id
);

This could have be

const [ user ] = useSWR('/api/user')
const [ projects ] = useSWR(
  () => '/api/projects?uid=' + user.id
);

And if you need other values:

const [data, error, isValidating, revalidate] = useSWR(URL, fetch)

I understand this could be a annoying if you want to use revalidate without isValidating or error but I think is more common to need multiple data with different names than reading those other values in isolation.

If useSWR is dependent on state, the return values are undefined

const Pokemon = () => {
  const [pokemon, setPokemon] = useState(null);

  const loadPokemon = (url) => setPokemon(url);

  const { data, error } = useSWR('https://pokeapi.co/api/v2/pokemon', fetch);
  const { pokemonData, pokemonError } = useSWR(pokemon, fetch);
  
  // This is null
  console.log(pokemonData, pokemonError)
  
  if (error) return <div>failed to load</div>
  if (!data) return <div>loading...</div>

  return <div>{data.results.map(pokemon => {
    return <h2 key={pokemon.name} onClick={() => loadPokemon(pokemon.url)}>{pokemon.name}</h2>
  })}

  </div>
}

Don't know what I am doing wrong. But the second useSWR is always undefined, even though I see the network calls going through.

Pre-commit and bundlesize

Guys, I see potential in that library, so I thought about adding basics thinks, but very useful during future development.
Do you mind if I will add pre-commit and bundlesize?

Suspense is not resolved and the requests are looping

import React, { Suspense } from 'react';
import useSWR from '@zeit/swr'

function StarWarsSuspense() {
  return (
    <Suspense fallback={<div>loading ...</div>}>
      <StarWars />
    </Suspense>
  )
}

function StarWars() {
  const { data } = useSWR('http://swquotesapi.digitaljedi.dk/api/SWQuote/RandomStarWarsQuote', fetch, { suspense: true });

  return (
    <div>
      {data.starWarsQuote}
    </div>
  );
}

export default StarWarsSuspense;

With this code, i never get the final component, the placeholder stay forever, looking on chrome developer console, the requests are looping.

I made this code using the readme example, i tried change de fetch function to a random promise to see if i get out of fallback, without no results.

I doing something wrong or this is really something that should not happen ?

Enabling Suspense hangs browser

I have tried to setup an example project using the SWR hook with GraphQL, as explained in the documentation. However, enabling suspense in the options of useSWR causes the browser to hang.

I have an example project on CodeSandbox which shows this. Simply go to either screens/movies.tsx or screens/movie-details.tsx and uncomment the line with the // { suspense: true }.

Example for `urql`?

Is anyone able to write an example for use with urql? I'm currently experimenting with swr, recently taking up the JAMstack mindset.

Suspense Mode

I noticed two problems with the suspense mode.

  1. The default example useSWR('/api', fetch, { suspense: true }) doesn't work because it returns a readable stream.

  2. When I modified the default example and returned data, I noticed, the component was rendered multiple times.

import React from 'react';
import useSWR from 'swr'

const FetchSuspense = endpoint => {
    console.log('calling me with', endpoint)
    return fetch(endpoint).then(data => data.json()).then(res => res.results[0])
}

export const Person = ({ resource, num  }) => {
     const { data } = useSWR('https://randomuser.me/api', FetchSuspense, { suspense: true })
     console.log("calling comp", num)
     return (<div>Loaded {num}: - {data.name.first}</div>)
};

Typescript keyInterface can't be null

Can't null the key unless I //@ts-ignore it

Argument of type 'string | null' is not assignable to parameter of type 'keyInterface'.
  Type 'null' is not assignable to type 'keyInterface'.  TS2345
  const { data: results, isValidating: loading } = useSWR(
    value ? `/api/search/autocomplete/${entity}/?query=${value}` : null,
    (url: string) => fetch(url).then(_ => _.json())
  );

Bug: Suspense Data undefined Race Condition

I'm not sure if this is a bug, or if this behavior is intended, but I was running into an issue with the line of code below.

So, I'm using useSWR(/api/users/${id}, fetch, {suspense: true}) where the key is dynamic based on the id of the object I want to get (in this contrived example the user's id).

My code looks something like this exampled:

function useUser(id) {
  const user = useSWR(`/api/users/${id}`, fetch, {suspense: true})
  console.log(user)
  return user
}

When this hook is called multiple times with different IDs, the logs would look like this:

// render 1 with user id 1
{ id:1 }
// render 2 with user id 2
undefined
// render 3
{ id: 2 }

The reason behind this is the two LOC referenced below.

So, my question is, in render 2 on L342 typeof data = Object, not undefined because the data is reset on line 358 (afterwards). Should there be a line before line 342 that checks to see if the keyRef.current and the new key are then different and reset data there so that the revalidate can happen immediately?

I quickly implemented this locally and this fixed my issue and prevented render 2 happening where the data was undefined.

Thanks! Loving this library so far.

https://github.com/zeit/swr/blob/9b51b7d066335d7249d114e2b9a2cb5d633795b6/src/use-swr.ts#L342
https://github.com/zeit/swr/blob/9b51b7d066335d7249d114e2b9a2cb5d633795b6/src/use-swr.ts#L358

Example about pagination

Wondering how I can apply pagination for my app using swr, I'm trying to use swr to implement infinite scroll for my web app and here are some questions:

  • The query parameters will change: page = 1 then page = 2, how can I update the cache accordingly

Thank you.

Performance discussion

Hi, This is an interesting hooks. However, keep re-validating the state by calling the Server API may casing the performance issues if there are many concurrent users. How could we handle this issue? shall we combine this with Redux?

Thanks and Regards
Duy

Triggering error with fetch?

How do you trigger the error state?
currently my errors are being returned in the data as data.error

const { data, error } = useSWR<API_BlogPost[], any>('/api/blog', fetch)

my api call

export default async (_req: NextApiRequest, res: NextApiResponse) => {
  try {
    const data: DB_BlogPost[] = await client.query(...my query)
    // @ts-ignore
    xds = 'lag' // this should return as an error because `xds` is not defined
    res.status(200).json(data)
  } catch (e) {
    // something went wrong eg the `xds` assignment in the try
    res.status(500).json({ error: e.message })
  }
}

and then the fetch helper

export default async function(...args: any) {
  // @ts-ignore
  const res = await fetch(...args)
  return await res.json()
}

which i'm trying to use as follow:

const Blog = () => {
  const { data, error } = useSWR<API_BlogPost[], any>('/api/blog', fetch)
  if (error) {
    return <div>My Error Component</div>
  }
  if (!data) {
    return <div>My Loading Component</div>
  }
  return <div>My Blog Component</div>
}

Support react-native NetInfo

Hello to all,
I noticed that the network status is detected only by navigator.onLine.

I wanted to propose the use of wora/netinfo (documentation). simple library that implements the reactive netinfo interface to use it also on the web, thanks to the work done by Nicolas Gallagher in react-native-web, in which I made changes to manage the SSR and integrate react-native versions.

Let me know if you are interested in its integration.

thanks,
Lorenzo

Support Non-String Keys

It would be useful for my usage of SWR to allow for non-string keys. I'm using database ids as keys which appear to be coerced to strings.

I would also like to use arrays/tuples as keys. For example: ['context', 12123908] to add differentiation. I presume this would require some kind of deeper equality check for cache invalidation etc.

Thoughts? Thanks!

Conditional fetching

Hey, thanks for putting together this library.

I'm curious how you think about conditional fetching since we can't use conditionals with React hooks. For example, say we have a storefront with a list of items. And if the current user has special access, each item will get augmented with a discount.

In totally invalid React pseudocode:

const {data: user} = userSWR(`/api/me`)
const {data: items} = useSWR(`/api/items`)

let discounts = []
if (user.isSpecial) {
  const {data} = useSWR(`/api/discounts`)
  if (data) { discounts = data }
}

return <ItemList items={items} discounts={discounts} />

Being able to pass fetch in gives us an escape hatch, but I'm not sure if that's how you intended it to be used.

const {data: user} = userSWR(`/api/me`)
const {data: items} = useSWR(`/api/items`)
const {data: discounts} = useSWR(`/api/discounts`, (query) => {
  if (user.isSpecial) {
    return fetch(query)
  } else {
    return []
  }
});

return <ItemList items={items} discounts={discounts} />

How would you go about implementing this pattern? Thanks!

Accept glob pattern or RegExp in trigger()

Thanks a lot for releasing this library! I'm just starting to play around with it but it seems like it's quite a simplification over what we're currently doing in our apps to fetch data.

I was wondering about one thing though: After a successful POST request you commonly need to revalidate some related data. If I got it right, you either do that with the revalidate() function that is returned from useSWR() or by calling trigger() with a key. The latter seems like a shortcut in cases where it'd be tedious to pass revalidate() around between components. However, in cases like these chances are that I also don't know the exact key (maybe because there's a bunch of dynamic parameters in there).

What do you think about also accepting something like a glob pattern or a RegExp as an argument to trigger() and then revalidating all the matching (and currently visible) queries? That way you could do trigger("/projects*") or trigger(/\/projects.*/) instead of the more specific trigger("/projects?page=3&perPage=100").

(I haven't checked out the implementation of SWR so please let me know if I have incorrect assumptions about the internals!)

global cache?

Is the key cache global? How does it handle conflicts if it's used in multiple contexts?

ERROR : fn is not a function

Hi! I'm trying to use swr, but this error keeps bugging me.
I installed packages with npm install --save react react-dom next and started project with next start.

And this is my fetch code. Of course I set cors configuration in my server.

import { NextComponentType } from 'next';
import useSWR from 'swr';

const FetchComponent: NextComponentType = () => {
  const { data, error } = useSWR('http://localhost:3000/user');
  return (
    <div>
      <div>{data ? `here data ${data}` : 'no data'}</div>
    </div>
  );
};

export default FetchComponent;

I expected some Json formatted data will be shown, but It shows undefined.
So I logged the error and found this error

TypeError: fn is not a function
    at use-swr.js:116
    at use-swr.js:193
    at commitHookEffectList (react-dom.development.js:21997)
    at commitLifeCycles (react-dom.development.js:22047)
    at commitLayoutEffects (react-dom.development.js:25302)
    at HTMLUnknownElement.callCallback (react-dom.development.js:336)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:385)
    at invokeGuardedCallback (react-dom.development.js:440)
    at commitRootImpl (react-dom.development.js:25040)
    at unstable_runWithPriority (scheduler.development.js:818)
    at runWithPriority$2 (react-dom.development.js:12130)
    at commitRoot (react-dom.development.js:24889)
    at finishSyncRender (react-dom.development.js:24296)
    at performSyncWorkOnRoot (react-dom.development.js:24274)
    at scheduleUpdateOnFiber (react-dom.development.js:23665)
    at updateContainer (react-dom.development.js:27061)
    at react-dom.development.js:27485
    at unbatchedUpdates (react-dom.development.js:24400)
    at legacyRenderSubtreeIntoContainer (react-dom.development.js:27484)
    at Object.hydrate (react-dom.development.js:27559)
    at renderReactElement (index.js:27)
    at _callee4$ (index.js:33)
    at tryCatch (runtime.js:45)
    at Generator.invoke [as _invoke] (runtime.js:271)
    at Generator.prototype.<computed> [as next] (runtime.js:97)
    at asyncGeneratorStep (asyncToGenerator.js:5)
    at _next (asyncToGenerator.js:27)
    at asyncToGenerator.js:34
    at new Promise (<anonymous>)
    at new F (_export.js:36)
    at asyncToGenerator.js:23
    at _doRender (index.js:33)
    at doRender (index.js:29)
    at _callee2$ (index.js:18)
    at tryCatch (runtime.js:45)
    at Generator.invoke [as _invoke] (runtime.js:271)
    at Generator.prototype.<computed> [as next] (runtime.js:97)
    at asyncGeneratorStep (asyncToGenerator.js:5)
    at _next (asyncToGenerator.js:27)
    at asyncToGenerator.js:34
    at new Promise (<anonymous>)
    at new F (_export.js:36)
    at asyncToGenerator.js:23
    at _render (index.js:18)
    at render (index.js:15)
    at _callee$ (index.js:15)
    at tryCatch (runtime.js:45)
    at Generator.invoke [as _invoke] (runtime.js:271)
    at Generator.prototype.<computed> [as next] (runtime.js:97)
    at asyncGeneratorStep (asyncToGenerator.js:5)

Pagination example with page numbers?

Our backend uses page number for pagination (first page is 0, second page is 1, and so on). What would be the correct way to implement that with useSWRPages()?

My current implementation works so that I'm using this as my swrDataToOffset function:

data => !data || !pages || pages.length === 0 ? 0 : pages.length - 1

Also, I'm not sure if it's a problem with my implementation, but as I'm trying useSWRPages() out in our Next.js application, I'm getting this exception when the application is hot reloaded (HMR) and there were several pages fetched before the reload:

Warning: Encountered two children with the same key, `page-2`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.

[Next] StrictMode

I started to use this library and I see a lot of potential in it! Thanks for the awesome work.

I use nextjs with StrictMode, so I started to notice the following message in my server-side logs:

Warning: useLayoutEffect does nothing on the server, because its effect cannot be encoded into the server renderer's output format. This will lead to a mismatch between the initial, non-hydrated UI and the intended UI. To avoid this, useLayoutEffect should only be used in components that render exclusively on the client. See https://fb.me/react-uselayouteffect-ssr for common fixes.

Is there anything I can do on my side to avoid those messages?

PS - If I understand correctly, you are using "useLayoutEffect" to avoid running on the server. If my assumption is correct, is there any benefit from using "useLayoutEffect", instead of "useEffect" with a check to see if we have window available? Sorry if this is a "dumb" question but I'm quite new to hooks :)

how does swr work with useEffect??request many times when props change.

it‘s my first time to use this library. useSWR('/api/data', fetchData) will excute when App props changes. how can i use useEffect let it only work in componentDidMount..it seems not work in useEffect.

import useSWR from 'swr'
import fetchData from './fetch-data'

function App () {
  const { data } = useSWR('/api/data', fetchData)
  // ...
}`
expect
`import useSWR from 'swr'
import fetchData from './fetch-data'

function App () {
useEffect(() => {
 const { data } = useSWR('/api/data', fetchData)
  // ...
}, [])
}

[Question] Async autocomplete example

I'm looking to implement SWR in a project but I'm wondering if it would be beneficial to use this for a type of async autocomplete component and if so how would that look, all the current examples are based on that you have static data that you get when rendering but how would it look when you have data you want to load based on what you type like a autocomplete?

Using GraphQL doesn't always revalidate

There's a problem with revalidating data in some circumstances which can be seen in this example project. This is based on the

  1. Navigate to a details page by clicking on one of the items.
  2. See the data load, and correctly show.
  3. Go back to the previous page.
  4. Click on another item.
  5. See that it sometimes doesn't revalidate/update the state for the given page.

Note that the project uses @reach/router which provides a param slug through the MovieDetailsScreen component, as it is a route component.

My theory is that the revalidation doesn't happen because the "key" (GraphQL) is always the same even though the provided variable changes and therefore doesn't revalidate, but I don't know exactly the inner workings of useSWR with regards to GraphQL.

Dependent fetching on list of urls

First of all, thanks 👍 for this awesome library. Heard about it on zeit's twiiter page this week and i wanted to try my hands on it.

This issue is related to #71 . In my case, i'll like to get info of each pokemon for each pokemon's url from the api, instead of displaying info based on a clicked pokemon.
I'm using the pokemon api as an example. demo is ➡️ codesandbox

Better types?

Types for the hook are fairly unhelpful:

declare function useSWR(...args: any[]): {
    error: any;
    data: any;
    revalidate: () => Promise<boolean>;
    isValidating: boolean;
};

Not sure if we can improve the args definition here

Avoiding waterfalls with Suspense

Side note: I am writing this with my jaw on the floor. What a clean API. Nice work guys. 😍

This issue refers to the idea of waterfalls as mentioned in the react docs.
https://reactjs.org/docs/concurrent-mode-suspense.html#for-library-authors

From a glance, it appears that the suspense based API does not take the above optimization into consideration. If I am not mistaken, to avoid waterfalls, we need to declare the API calls first(which will init the fetch calls), and then read the data from another call (read method in relay), which will throw the promise.

Is this already done in the library? If not, do you guys plan to do it in the future? How would the API look like?


PS: In my head, the API should look something like below

function MyComponent(props) {
    // First we declare the list of fetch calls. Here we use an object. Could be an array instead.
    // Doing this will NOT trigger suspense. i.e. A promise shall not be thrown.
    // But the API calls will be triggered in parallel  
    const fetcher = useSuspenseSwr({
         key1: {/*fetch config for key 1*/},
         key2: {/*fetch config for key 2*/},
    });

    // and then call fetcher.fetch('key1') somewhere in the code
    // This is when the promise will be thrown
}

Describe installation process

README should contain steps to install and use package.
Ideally at the beginning right after small package description.

yarn add swr - will it work?
yarn add zeit/swr - maybe this one?

How do I know which package belongs to which author?
How to verify I install your package and not some fake one?

Support multiple caching mechanisms

Frontend based:

  • Memory (Map, the current cache mechanism)
  • Session Storage
  • Local Storage
  • WebSQL
  • IndexedDb

Backend Based:

  • sqlite
  • LRUCache
  • Redis
  • Anything...?

Suggestion

My suggestion would be to allow providing a class that implements a new interface that supports a similar API to Map (get, set, delete?), defaulting to a MemoryCache that just uses Map

Side Notes

Frontend based caches could help add support for persistence.
Backend based caches could help with adding support for SSR.

This could also add the possibility for supporting TTLs if that's desired, potentially solving #4
Can also solve #7 by allowing users the track their own namespaces.

As suggested by @netspencer, a layered cache architecture could be awesome too

After reading #4 it looks like you might already be planning this, which is awesome!

Remove old cached items

Hi great library. Is there any way to delete old cache items to avoid using up lots of memory? For example in an app with lots of pages where you want to cache if the user presses back but they are unlikely to go back more than 10. Perhaps this could be written in user space by using mutate(key, null) ?

How does one defer execution?

Is there an option to defer execution? For example, what if I want only want to fetch the resource (and make the network request) when the user clicks on "fetch"?

For fun: JetSet

SWR is awesome! In a previous chapter of my career our team undertook a similar project at one point (pre-hooks, using HOCs) -- https://github.com/DigitalGlobe/jetset -- but didn't land on nearly the level of sophistication and elegance you have achieved here. Huge props to you and the team! 💪

Ability to use SQLite as cache?

Upon first glance, I feel that swr could potential be a great tool to use for offline applications. Is there a way to sync the cache with SQLite or perhaps even use SQLite as the cache?

Using query params

Hi there,

Thanks for this little library ! After exploring the doc I could not find a way to invalidate multiple entries at once. For example, if I've a search bar /projects?description=My Search, when adding a new project I would like to invalidate all /projects/*.

Any idea how this could be implemented?

Add umd/es6 module exports

This is a feature request.

Even though cjs+babel is the most common way to import modules, a number of projects out there use a es2015-style module imports. Like many libraries out there (like React), it'd be great if there's a umd export available for swr.

Cache issue - can't get new data with either `trigger` or `revalidate`

Really like the idea of useSWR, really wish I could get it to work :-(

Here's what I'm doing:

    const { data: userId, error: userIdError } = useSWR(
        `/user-id/${authenticateMachine.userName}`,
        () => theThingStore.getUserId(authenticateMachine.userName)
    )
    const { data: things, error: thingsError } = useSWR(
        `/things/${userId}`,
        () => theThingStore.getCurrentThingsFromDb(userId)
    )

    const doAddNewThing = () => {
        const myInit = {
            body: {
                userTitle: `Thing ${new Date().toJSON()
                    .substr(11, 8)
                    .split(':')
                    .join('-')}`,
            },
            headers: {
                'Content-Type': 'application/json',
            },
        }

        return API.post(API_NAME, `/add-new-thing`, myInit)
            .then((data) => {
                console.log('add-new-thing returned', data)
                setTimeout(() => {
                    console.log('Doing trigger to get new content.')
                    trigger(`/things`)
                }, 2000)
            })
            .catch((err) => {
                console.log('add-new-thing failed with error', err)
            })
    }

    // react code to display the things list.

For the trigger call, I've tried:

    trigger('/things')
    trigger(`/things/${userId}`)

I've also tried revalidate instead of trigger.

I thought that would cause a re-fetch of my data, and show me the new data. However,
it does not call my getCurrentThingsFromDb method after the trigger runs.
My list of items remains the ones before the add.

In fact, if I reload the page, it keeps the old data!

I've got a "run a curl every half-second" process running next to the browser, and
it sees the number of things increase, so I know that the API is returning the right
data; after the API.post, and before the trigger, there's new data arriving at
my machine.

I originally wasn't using the setTimeout; longer timeouts don't help.

Thanks!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.