A plugin (or middleware) can extend the configuration, key, and fetcher function of SWR. With this feature we can make SWR lightweight and more customizable.
import swrAxios from 'swr-axios'
import useSWR from 'swr'
// ...
useSWR('key', fetcher, { use: swrAxios })
You can use multiple plugins too:
useSWR('key', fetcher, { use: [...plugins] }
Or pass them to the context:
<SWRConfig value={{ use: [...plugins] }}>
swrAxios should be a function, which accepts all the params passed to the SWR hook, and return the extended ones:
function swrAxios (key, fetcher, config) {
...
return [newKey, newFetcher, newConfig]
}
That way, middleware can be chained, and you will also be able to use custom configs too (because they'll be passed to the handlers).
fetch polyfill, or isomorphic-fetch, etc.)@quietshu
Great idea. Thank you.
It seems converting this repo to a monorepo first to contain at least official plugins like swr-axios should be the task prior to this one.
I'm not sure but I think this could happen on user-land? Create a useExtendedSWR on your project or publishing it to npm and that will work as a middleware/plugin.
Leaving swr-axios on the user-land would mean the necessity to manage multiple repos, making it more difficult to keep the plugins up-to-date, given the fast pace of features being added to swr.
I believe, in any typical frontend project that works with a RESTful API, you would expect to see either axios or request libs to be used to send HTTP requests.
If you guys agree, I can provide with a separate PR to make it a monorepo.
I don't mean making swr-axios in user land, I mean don't adding support for this since it could happen in user land.
function useSWRAxios(...args) {
// do something here to extend or reduce args
return useSWR(...newArgs)
}
It's not hard to write a wrapper around a hook creating a new hook and support composition.
@sergiodxa I believe you missed the related issues above that indicate a more complicated use case, especially for axios.
I participate in discussions in other libs like react-async, react-query.
The major concern people have is the complicated scenarios with query string params, etc. that would make the work with a key param of useSWR complicated.
That's why @Svish introduced his idea with JSON.stringify of the axios request and I discussed a more general approach that everyone could build on top https://github.com/zeit/swr/issues/166#issuecomment-561423398
@sergiodxa sorry for the noise, I believe I didn't provide enough arguments, so let me reply to you:
It's not hard to write a wrapper around a hook creating a new hook and support composition.
Look at the amount of work done in #145
And the funny thing, that solution is still imperfect, as well as my proposal also has issues https://github.com/zeit/swr/issues/166#issuecomment-561423398
Why not to combine efforts to seek the best practices, instead of everyone creating the same imperfect solutions over and over in their own repos?
馃 I think I get it, I'm still unsure about having plugins support in useSWR, maybe this repo could be a monorepo as you said and have two or more libs:
So if you want only SWR you yarn add swr, but if you want to use it with axios you could install yarn add swr swr-axios and if you want SWR with another integration you could yarn add swr swr-*.
And all of these extra packages could be custom hooks using useSWR internally (they could set swr as peer dependency too) so you don't need custom plugins support in SWR, compose the hooks creating new hooks, this way you don't need to add an extra feature to SWR, and you could still have a better single implementation of how to integrate SWR with Axios (and other fetching libs).
Also those swr-* could not only be here, but be in other repos, so you could publish your own wrapper around SWR to integrate it with another library, as a lot of Redux libraries did, eventually officially supported implementations could be moved to this repo or be recommended in the README.
What do you think? @o-alexandrov @quietshu
I'm mostly worry about adding a feature that could not be really necessary since hooks allow composability and specially it's probably not going to be used by ZEIT, I like that SWR comes from ZEIT internal usage since that guarantees me you are going to keep maintaining the lib and those features.
@sergiodxa
This is exactly what I would love to see in this project to happen.
@quietshu I could propose a PR with a monorepo setup of lerna + yarn workspaces:
@sergiodxa I believe you have a typo:
maybe this repo could be a monorepo as you said and have two libs:
馃憖
What's going on with this issue?
Allow me to tell you about my complicated pattern. I use SWR with ky. request<T> extends kyHttpClient for firebase.User and locale and so on.
https://github.com/sindresorhus/ky/blob/764bc1cdabdb65bbcd9830b0f8bfbd95fed3179a/index.d.ts#L159
// ky鈥檚 option
type RequestOptions = Options;
type AdditionalRequestOptions = {
locale?: ja | en;
firebaseUser?: firebase.User;
forceRefreshToken?: boolean;
};
/**
* For auth required endpoints
*/
export const useSWRRequestWithFirebaseUser = <T>(
url: string | null,
options: RequestOptions,
additionalOpts: AdditionalRequestOptions,
swrConfig?: CustomSwrConfig<T>
) => {
const { locale } = additionalOpts;
return useSWR<T>(
url && additionalOpts?.firebaseUser
? `${url}${JSON.stringify({ locale, ...options })}`
: null,
() => request<T>(url || "", options, additionalOpts),
swrConfig
);
};
/**
* For auth optional endpoints
*/
export const useSWRRequestWithOrWithoutFirebaseUser = <T>(
url: string,
options: RequestOptions,
additionalOpts: AdditionalRequestOptions,
swrConfig?: CustomSwrConfig<T>
) => {
const { locale } = additionalOpts;
return useSWR<T>(
`${url}${JSON.stringify({ locale, ...options })}`,
() => request<T>(url, options, additionalOpts),
swrConfig
);
};
Using SWR with HttpClient and Auth library become complicated. 馃槶
Thank you for sharing your use case here @matamatanot, it鈥檚 very helpful!
I think instead of using a middleware, we can think about adding a new option serialize:
useSWR([url, opts], fetcher, { serialize: true })
@shuding Thanks! A new option serialize seem to be very useful. I would love to see the option added to the library.
But, I think there is a better way.
firebase.User is a little large object. Serializing a firebase.User object go too far. For many people, what we want to achieve is that if a user logs out or switches to another account, the cache will not be returned.
I see @matamatanot! While serialize is helpful, what we can do is to provide another option disable, which is an alternative to useSWR(null, fetcher) like what you are doing.
Most helpful comment
馃 I think I get it, I'm still unsure about having plugins support in useSWR, maybe this repo could be a monorepo as you said and have two or more libs:
So if you want only SWR you
yarn add swr, but if you want to use it with axios you could installyarn add swr swr-axiosand if you want SWR with another integration you couldyarn add swr swr-*.And all of these extra packages could be custom hooks using
useSWRinternally (they could setswras peer dependency too) so you don't need custom plugins support in SWR, compose the hooks creating new hooks, this way you don't need to add an extra feature to SWR, and you could still have a better single implementation of how to integrate SWR with Axios (and other fetching libs).Also those
swr-*could not only be here, but be in other repos, so you could publish your own wrapper around SWR to integrate it with another library, as a lot of Redux libraries did, eventually officially supported implementations could be moved to this repo or be recommended in the README.What do you think? @o-alexandrov @quietshu
I'm mostly worry about adding a feature that could not be really necessary since hooks allow composability and specially it's probably not going to be used by ZEIT, I like that SWR comes from ZEIT internal usage since that guarantees me you are going to keep maintaining the lib and those features.