Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

swr

Package Overview
Dependencies
Maintainers
55
Versions
162
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

swr - npm Package Compare versions

Comparing version 0.1.8 to 0.1.9

dist/libs/hash.d.ts

3

dist/libs/is-document-visible.js

@@ -6,4 +6,3 @@ "use strict";

typeof document.visibilityState !== 'undefined') {
return (document.visibilityState === 'visible' ||
document.visibilityState === 'prerender');
return document.visibilityState !== 'hidden';
}

@@ -10,0 +9,0 @@ // always assume it's visible

@@ -22,6 +22,6 @@ export interface ConfigInterface<Data = any, Error = any> {

declare type keyFunction = () => string;
export declare type keyInterface = string | keyFunction;
export declare type keyInterface = string | keyFunction | any[] | null;
export declare type updaterInterface<Data = any, Error = any> = (shouldRevalidate?: boolean, data?: Data, error?: Error) => boolean | Promise<boolean>;
export declare type triggerInterface = (key: string, shouldRevalidate?: boolean) => void;
export declare type mutateInterface<Data = any> = (key: string, data: Data, shouldRevalidate?: boolean) => void;
export declare type triggerInterface = (key: keyInterface, shouldRevalidate?: boolean) => void;
export declare type mutateInterface<Data = any> = (key: keyInterface, data: Data, shouldRevalidate?: boolean) => void;
export declare type broadcastStateInterface<Data = any, Error = any> = (key: string, data: Data, error?: Error) => void;

@@ -41,3 +41,3 @@ export declare type responseInterface<Data, Error> = {

export declare type pageComponentType<Offset, Data, Error> = (props: pagesPropsInterface<Offset, Data, Error>) => any;
export declare type pageOffsetMapperType<Offset, Data, Error> = (data: any, pageSWRs: responseInterface<Data, Error>[]) => Offset;
export declare type pageOffsetMapperType<Offset, Data, Error> = (SWR: responseInterface<Data, Error>, index: number) => Offset;
export declare type pagesResponseInterface = {

@@ -44,0 +44,0 @@ pages: any;

import { pagesResponseInterface, pageComponentType, pageOffsetMapperType } from './types';
export declare function useSWRPages<OffsetType, Data, Error>(pageKey: string, pageFn: pageComponentType<OffsetType, Data, Error>, swrDataToOffset: pageOffsetMapperType<OffsetType, Data, Error>, deps?: any[]): pagesResponseInterface;
export declare function useSWRPages<OffsetType, Data, Error>(pageKey: string, pageFn: pageComponentType<OffsetType, Data, Error>, SWRToOffset: pageOffsetMapperType<OffsetType, Data, Error>, deps?: any[]): pagesResponseInterface;

@@ -91,3 +91,3 @@ "use strict";

*/
function useSWRPages(pageKey, pageFn, swrDataToOffset, deps = []) {
function useSWRPages(pageKey, pageFn, SWRToOffset, deps = []) {
const pageCountKey = `_swr_page_count_` + pageKey;

@@ -139,16 +139,16 @@ const pageOffsetKey = `_swr_page_offset_` + pageKey;

_swrs[id] = swr;
if (typeof swr.data !== 'undefined') {
// set next page's offset
const newPageOffset = swrDataToOffset(swr.data, _swrs);
if (pageOffsets[id + 1] !== newPageOffset) {
setPageOffsets(arr => {
const _arr = [...arr];
_arr[id + 1] = newPageOffset;
config_1.cacheSet(pageOffsetKey, _arr);
return _arr;
});
}
}
return _swrs;
});
if (typeof swr.data !== 'undefined') {
// set next page's offset
const newPageOffset = SWRToOffset(swr, id);
if (pageOffsets[id + 1] !== newPageOffset) {
setPageOffsets(arr => {
const _arr = [...arr];
_arr[id + 1] = newPageOffset;
config_1.cacheSet(pageOffsetKey, _arr);
return _arr;
});
}
}
}

@@ -155,0 +155,0 @@ return swr;

@@ -15,3 +15,3 @@ "use strict";

const reactBatchedUpdates_1 = require("./libs/reactBatchedUpdates");
const lodash_throttle_1 = __importDefault(require("lodash.throttle"));
const throttle_1 = __importDefault(require("lodash/throttle"));
const fast_deep_equal_1 = __importDefault(require("fast-deep-equal"));

@@ -22,6 +22,33 @@ const config_1 = __importStar(require("./config"));

const use_hydration_1 = __importDefault(require("./libs/use-hydration"));
const hash_1 = __importDefault(require("./libs/hash"));
const IS_SERVER = typeof window === 'undefined';
// TODO: introduce namepsace for the cache
const getErrorKey = key => (key ? 'err@' + key : '');
const trigger = (key, shouldRevalidate = true) => {
const getKeyArgs = _key => {
let key;
let args = null;
if (typeof _key === 'function') {
try {
key = _key();
}
catch (err) {
// dependencies not ready
key = '';
}
}
else if (Array.isArray(_key)) {
// args array
key = hash_1.default(_key);
args = _key;
}
else {
// convert null to ''
key = String(_key || '');
}
return [key, args];
};
const trigger = (_key, shouldRevalidate = true) => {
const [key] = getKeyArgs(_key);
if (!key)
return;
const updaters = config_1.CACHE_REVALIDATORS[key];

@@ -45,3 +72,4 @@ if (key && updaters) {

};
const mutate = (key, data, shouldRevalidate = true) => {
const mutate = (_key, data, shouldRevalidate = true) => {
const [key] = getKeyArgs(_key);
if (!key)

@@ -79,16 +107,3 @@ return;

// (because `revalidate` only depends on `key`)
let key;
if (typeof _key === 'function') {
try {
key = _key();
}
catch (err) {
// dependencies not ready
key = '';
}
}
else {
// convert null to ''
key = String(_key || '');
}
const [key, fnArgs] = getKeyArgs(_key);
// `keyErr` is the cache key for error objects

@@ -143,3 +158,8 @@ const keyErr = getErrorKey(key);

}
config_1.CONCURRENT_PROMISES[key] = fn(key);
if (fnArgs !== null) {
config_1.CONCURRENT_PROMISES[key] = fn(...fnArgs);
}
else {
config_1.CONCURRENT_PROMISES[key] = fn(key);
}
config_1.CONCURRENT_PROMISES_TS[key] = startAt = Date.now();

@@ -257,3 +277,3 @@ setTimeout(() => {

// and tabs being switched quickly
onFocus = lodash_throttle_1.default(softRevalidate, config.focusThrottleInterval);
onFocus = throttle_1.default(softRevalidate, config.focusThrottleInterval);
if (!config_1.FOCUS_REVALIDATORS[key]) {

@@ -260,0 +280,0 @@ config_1.FOCUS_REVALIDATORS[key] = [onFocus];

{
"name": "swr",
"version": "0.1.8",
"version": "0.1.9",
"description": "React Hooks library for remote data fetching",

@@ -38,3 +38,3 @@ "main": "./dist/index.js",

"@types/jest": "24.0.20",
"@types/lodash.throttle": "4.1.6",
"@types/lodash": "4.14.145",
"@types/node": "11.12.0",

@@ -58,3 +58,3 @@ "@types/react": "16.9.11",

"fast-deep-equal": "2.0.1",
"lodash.throttle": "4.1.1",
"lodash": "4.17.15",
"ms": "2.1.2"

@@ -61,0 +61,0 @@ },

[![SWR](https://assets.zeit.co/image/upload/v1572289618/swr/banner.png)](https://swr.now.sh)
<p align="center">
<a aria-label="SWR website" href="https://swr.now.sh">swr.now.sh<a>
</p>
<p align="center">
<a aria-label="ZEIT logo" href="https://github.com/zeit">

@@ -22,7 +18,9 @@ <img src="https://img.shields.io/badge/MADE%20BY%20ZEIT-000000.svg?logo=ZEIT&labelColor=000000&logoWidth=12">

## Intro
## Introduction
[swr.now.sh](https://swr.now.sh)
SWR is a React Hooks library for remote data fetching.
The name “**SWR**” is derived from `stale-while-revalidate`, a HTTP cache invalidation strategy popularized by [RFC 5861](https://tools.ietf.org/html/rfc5861).
The name “**SWR**” is derived from `stale-while-revalidate`, a HTTP cache invalidation strategy popularized by [RFC 5861](https://tools.ietf.org/html/rfc5861).
**SWR** first returns the data from cache (stale), then sends the fetch request (revalidate), and finally comes with the up-to-date data again.

@@ -41,8 +39,8 @@

With SWR, components will get a stream of data updates constantly and automatically, Thus, the UI will be always fast and reactive.
...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**.
## Quick Start
To install, run `yarn add swr` or `npm install swr` in your React project.
```js

@@ -61,3 +59,3 @@ import useSWR from 'swr'

In this example, the React Hook `useSWR` accepts a `key` and a `fetcher` function.
`key` is a unique identifier of the data, normally a URL of the API. And the `fetcher` accepts
`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.

@@ -72,80 +70,134 @@

---
Check out [swr.now.sh](https://swr.now.sh) for more demos of SWR.
- API
- [`useSWR`](#useswr)
- [`SWRConfig`](#swrconfig)
- [`mutate`](#mutate)
- [`trigger`](#trigger)
- Examples
- [Suspense Mode](#suspense-mode)
- [Subscription (e.g.: socket.io)](#subscription-eg-socketio)
- [Dependent Fetching](#dependent-fetching)
## Usage
## API
Inside your React project directory, run the following:
### `useSWR`
```
yarn add swr
```
```js
const {
data, // data for the given key (or undefined)
error, // error (or undefined)
isValidating, // if the request is loading
revalidate // function to trigger a validate manually
} = useSWR(
key, // a unique key for the data (or a function, see below)
fetcher, // Promise returning function to load your data
swrOptions? = {
suspense: false, // enabled React Suspense mode
revalidateOnFocus: true, // auto revalidate when window gets focused
refreshWhenHidden: false, // refresh while the window is invisible
shouldRetryOnError: true, // retry when fetcher has an error
refreshInterval: 0, // polling interval (disabled by default)
errorRetryInterval: 5000, // error retry interval (10s on slow network)
focusThrottleInterval: 5000, // keep focus revalidate requests in a time window
dedupingInterval: 2000, // deduping requests
loadingTimeout: 3000, // timeout for triggering the onLoadingSlow event
Or with npm:
onLoadingSlow, // event handlers
onSuccess,
onError,
onErrorRetry,
```
npm install swr
```
fetcher // default fetcher function
}
)
### API
```js
const { data, error, isValidating, revalidate } = useSWR(key, fetcher, options)
```
#### `key` as a function
#### Parameters
Pass a function as the `key` to `useSWR` to conditionally fetch data. If the functions throws an error or returns a falsy value, SWR will cancel the request.
- `key`: a unique key string for the request (or a function / null) [(advanced usage)](#conditional-fetching)
- `fetcher`: (_optional_) a Promise returning function to fetch your data [(details)](#data-fetching)
- `options`: (_optional_) an object of options for this SWR hook
#### Return Values
- `data`: data for the given key resolved by `fetcher` (or undefined if not loaded)
- `error`: error thrown by `fetcher` (or undefined)
- `isValidating`: if there's a request or revalidation loading
- `revalidate`: function to trigger the validation manually
#### Options
- `suspense = false`: enable React Suspense mode [(details)](#suspense-mode)
- `fetcher = undefined`: the default fetcher function
- `revalidateOnFocus = true`: auto revalidate when window gets focused
- `refreshInterval = 0`: polling interval (disabled by default)
- `refreshWhenHidden = false`: polling when the window is invisible (if `refreshInterval` is enabled)
- `shouldRetryOnError = true`: retry when fetcher has an error [(details)](#error-retries)
- `dedupingInterval = 2000`: dedupe requests with the same key in this time span
- `focusThrottleInterval = 5000`: only revalidate once during a time span
- `loadingTimeout = 3000`: timeout to trigger the onLoadingSlow event
- `errorRetryInterval = 5000`: error retry interval [(details)](#error-retries)
- `onLoadingSlow`: callback function when a request takes too long to load (`loadingTimeout`)
- `onSuccess`: callback function when a request finishs successfully
- `onError`: callback function when a request returns an error
- `onErrorRetry`: handler for [error retry](#error-retries)
When under a slow network (2G, <= 70Kbps), `errorRetryInterval` will be 10s, and
`loadingTimeout` will be 5s by default.
You can also use [global configuration](#global-configuration) to provide default options.
## Examples
- [Global Configuration](#global-configuration)
- [Data Fetching](#data-fetching)
- [Conditional Fetching](#conditional-fetching)
- [Dependent Fetching](#dependent-fetching)
- [Manually Revalidate](#manually-revalidate)
- [Local Mutation](#local-mutation)
- [Suspense Mode](#suspense-mode)
- [Error Retries](#error-retries)
### Global Configuration
You can use `SWRConfig` to provide global configurations (`options`) for all SWR hooks.
In this example, all `useSWR` hooks will use the same fetcher provided to load JSON data, and refresh every 3 seconds (except the user API):
```js
// key returns a falsy value
const { data } = useSWR(() => shouldFetch ? '/api/data' : null, fetcher)
import useSWR, { SWRConfig } from 'swr'
// key throws an error when user.id is not defined
const { data } = useSWR(() => '/api/data?uid=' + user.id, fetcher)
function Dashboard () {
const { data: events } = useSWR('/api/events')
const { data: projects } = useSWR('/api/projects')
const { data: user } = useSWR('/api/user', { refreshInterval: 0 })
// ...
}
function App () {
return (
<SWRConfig
value={{
refreshInterval: 3000,
fetcher: (...args) => fetch(...args).then(res => res.json())
}}
>
<Dashboard />
</SWRConfig>
)
}
```
### `SWRConfig`
### Data Fetching
A context to provide global configurations (`swrOptions`) for SWR.
`fetcher` is a function **accepts the `key`** of SWR, and returns a value or a Promise.
You can use any library you to handle data fetching, for example:
```js
import useSWR, { SWRConfig } from 'swr'
import fetch from 'unfetch'
const fetcher = url => fetch(url).then(r => r.json())
function App () {
// all the SWRs inside will use `refreshInterval: 1000`
// and the native `fetch` implementation
return <SWRConfig value={{
refreshInterval: 1000,
fetcher: (...args) => fetch(...args).then(res => res.json())
}}>
<Profile/>
</SWRConfig>
const { data } = useSWR('/api/data', fetcher)
// ...
}
```
function Profile () {
const { data, error } = useSWR('/api/user')
Or using GraphQL:
```js
import { request } from 'graphql-request'
const API = 'https://api.graph.cool/simple/v1/movies'
const fetcher = query => request(API, query)
function App () {
const { data, error } = useSWR(
`{
Movie(title: "Inception") {
releaseDate
actors {
name
}
}
}`,
fetcher
)
// ...

@@ -155,27 +207,38 @@ }

### `mutate`
Note that `fetcher` can be skipped from the parameters if it's provided gloablly.
With `mutate`, you can update your local data programmatically, while
revalidating and finally replace it.
### Conditional Fetching
Use `null` or pass a function as the `key` to `useSWR` to conditionally fetch data. If the functions throws an error or returns a falsy value, SWR will cancel the request.
```js
import useSWR, { mutate } from 'swr'
// conditionally fetch
const { data } = useSWR(shouldFetch ? '/api/data' : null, fetcher)
function Profile () {
const { data } = useSWR('/api/user', fetcher)
// ...or return a falsy value
const { data } = useSWR(() => shouldFetch ? '/api/data' : null, fetcher)
return <div>
<h1>My name is {data.name}.</h1>
<button onClick={async () => {
const newName = data.name.toUpperCase()
// send a request to the API to update the data
await requestUpdateUsername(newName)
// update the local data immediately and revalidate (refetch)
mutate('/api/user', { ...data, name: newName })
}}>Uppercase my name!</button>
</div>
// ... or throw an error when user.id is not defined
const { data } = useSWR(() => '/api/data?uid=' + user.id, fetcher)
```
### Dependent Fetching
SWR also allows you to fetch data that depends on other data. It ensures the maximum possible parallelism (avoiding waterfalls), as well as serial fetching when a piece of dynamic data is required for the next data fetch to happen.
```js
function MyProjects () {
const { data: user } = useSWR('/api/user')
const { data: projects } = useSWR(() => '/api/projects?uid=' + user.id)
// When passing a function, SWR will use the
// return value as `key`. If the function throws,
// SWR will know that some dependencies are not
// ready. In this case it is `user`.
if (!projects) return 'loading...'
return 'You have ' + projects.length + ' projects'
}
```
### `trigger`
### Manually Revalidate

@@ -185,2 +248,5 @@ You can broadcast a revalidation message to all SWR data inside any component by calling

This example shows how to automatically refetch the login info (e.g.: inside `<Profile/>`)
when the user clicks the “Logout” button.
```js

@@ -190,21 +256,51 @@ import useSWR, { trigger } from 'swr'

function App () {
return <div>
<Profile />
<button onClick={() => {
// set the cookie as expired
document.cookie = 'token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;'
// tell all SWRs with this key to revalidate
trigger('/api/user')
}}>
Logout
</button>
</div>
return (
<div>
<Profile />
<button onClick={() => {
// set the cookie as expired
document.cookie = 'token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;'
// tell all SWRs with this key to revalidate
trigger('/api/user')
}}>
Logout
</button>
</div>
)
}
```
## Examples
### Local Mutation
In many cases, applying local mutations to data is a good way to make changes
feel faster — no need to wait for the remote source of data.
With `mutate`, you can update your local data programmatically, while
revalidating and finally replace it with the latest data.
```js
import useSWR, { mutate } from 'swr'
function Profile () {
const { data } = useSWR('/api/user', fetcher)
return (
<div>
<h1>My name is {data.name}.</h1>
<button onClick={async () => {
const newName = data.name.toUpperCase()
// send a request to the API to update the data
await requestUpdateUsername(newName)
// update the local data immediately and revalidate (refetch)
mutate('/api/user', { ...data, name: newName })
}}>Uppercase my name!</button>
</div>
)
}
```
### Suspense Mode
You can enable the `suspense` option to use `useSWR` with React Suspense.
You can enable the `suspense` option to use SWR with React Suspense:

@@ -221,62 +317,31 @@ ```js

function App () {
return <Suspense fallback={<div>loading...</div>}>
<Profile/>
</Suspense>
return (
<Suspense fallback={<div>loading...</div>}>
<Profile/>
</Suspense>
)
}
```
### Subscription (e.g.: socket.io)
Note in Suspense mode, `data` is always the fetch response (so you don't need to check if it's `undefined`). But if there's an error occurred, you need to use an [error boundary](https://reactjs.org/docs/concurrent-mode-suspense.html#handling-errors) to catch it.
You can use SWR with socket.io (generally any subscription pattern) like this:
### Error Retries
```js
// fetch-data.js
By default, SWR uses the [exponential backoff algorithm](https://en.wikipedia.org/wiki/Exponential_backoff) to handle error retries.
You can read more from the source code.
import { mutate } from 'swr'
It's also possible to override the behavior:
let latestData = null
```js
useSWR(key, fetcher, {
onErrorRetry: (error, key, option, revalidate, { retryCount }) => {
if (retryCount >= 10) return
if (error.status === 404) return
// setup ws and broadcast to all SWRs
...
socket.on('data', data => {
latestData = data
mutate('/api/data', data, false)
// retry after 5 seconds
setTimeout(() => revalidate({ retryCount: retryCount + 1 }), 5000)
}
})
export default () => latestData
```
and your component:
```js
import useSWR from 'swr'
import fetchData from './fetch-data'
function App () {
const { data } = useSWR('/api/data', fetchData)
// ...
}
```
### Dependent Fetching
SWR allows you to fetch data that depends on other data. It ensures the maximum possible parallelism (avoiding waterfalls), as well as serial fetching when a piece of dynamic data is required for the next data fetch to happen.
```js
import useSWR from 'swr'
function MyProjects () {
const { data: user } = useSWR('/api/user')
const { data: projects } = useSWR(
() => '/api/projects?uid=' + user.id
)
// When passing a function, SWR will use the
// return value as `key`. If the function throws,
// SWR will know that some dependencies are not
// ready. In this case it is `user`.
if (!projects) return 'loading...'
return 'You have ' + projects.length + ' projects'
}
```
## Authors

@@ -283,0 +348,0 @@ - Shu Ding ([@shuding_](https://twitter.com/shuding_)) – [ZEIT](https://zeit.co)

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc