Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Example for axios #143

Closed
Svish opened this issue Nov 21, 2019 · 12 comments
Closed

Example for axios #143

Svish opened this issue Nov 21, 2019 · 12 comments
Labels
documentation Improvements or additions to documentation question

Comments

@Svish
Copy link
Contributor

Svish commented Nov 21, 2019

With axios it's handy to "define requests" using a request object, for example like this:

import axios, { AxiosRequestConfig } from 'axios';

const request: AxiosRequestConfig = {
  baseURL: 'https://api.example.com',
  withCredentials: true,
  method: 'GET',
  url: '/search',
  params: {
    term: 'foobar',
  },
};

const response = await axios(request);
const data = response.data;

But from what I can gather, the key I can pass in to useSWR has to be a string? I can't find any of your included examples that uses anything other than a simple string either. In the readme, there's a short mention of using arrays, which can include both strings and objects, but it doesn't mention what the fetcher would actually look like, and it also says the key comparison is shallow, so with my request object above here, I assume that means a change in request.params.term would not be picked up?

Would it be possible for someone to add an example of how one can use useSWR with axios and a request object like this? Or is it perhaps not possible to do that?

@shuding
Copy link
Member

shuding commented Nov 21, 2019

When using an array as the key, SWR will pass those items as arguments to the fetcher function:

useSWR([A, B, C, ...], fetcher)
// calls fetcher(A, B, C, ...)

For your specific case, I'd do something like:

// global config because this part won't change
const getRequest: AxiosRequestConfig = {
  baseURL: 'https://api.example.com',
  withCredentials: true,
  method: 'GET'
};

function App () {
  // inside component
  const params = useMemo(() => ({ term }), [term])
  useSWR(
    ['/search', params],
    (url, params) => axios({ ...getRequest, url, params }).then(res => res.data)
  )
}

or simpler:

// global config because this part won't change
const getRequest: AxiosRequestConfig = {
  baseURL: 'https://api.example.com',
  withCredentials: true,
  method: 'GET'
};

const fetchTerm = (url, term) =>
  axios({ ...getRequest, url, params: { term } }).then(res => res.data)

function App () {
  // inside component
  useSWR(['/search', term], fetchTerm)
}

The major reason of shallow comparison is performance. So it will always render faster, and it will reuse the stale data if the same url + params pair has occurred before.

Thanks for the feedback! We will definitely improve the readme and create an example for axios.

@shuding shuding added question documentation Improvements or additions to documentation labels Nov 21, 2019
@Svish
Copy link
Contributor Author

Svish commented Nov 21, 2019

@quietshu Thank you for a quick reply!

In your example you have pulled the params out of the request object, which I was hoping to avoid as it's super useful to have it all contained in one request object. I definitely get the need for performance, but for small objects like these, would a deep equality check really be much slower? Would it maybe be possible to add the option of switching to a deep equality check?

@shuding
Copy link
Member

shuding commented Nov 21, 2019

@Svish I see your point 👍 I think this might be helpful then:

// let url = '/search'
// let term = 'foobar'

useSWR([url, term], () => axios({
  baseURL: 'https://api.example.com',
  withCredentials: true,
  method: 'GET',
  url,
  params: { term }
}).then(res => res.data))

key is just an indicator of this specific request, you can totally ignore it from the fetcher params. Just make sure the request will always be associated with the key (if key changes, the request will change).

@Svish
Copy link
Contributor Author

Svish commented Nov 21, 2019

So, would something along the following work? 🤔

// useRequest.js
export default function useRequest(request, config) {
  const { data: response, error, isValidating, revalidate } = useSWR(
    JSON.stringify(request),
    () => axios(request),
    config
  );

  return {
    data: response && response.data,
    response,
    error,
    isValidating,
    revalidate,
  };
}
const { data } = useRequest({
  baseURL: 'https://api.example.com',
  withCredentials: true,
  method: 'GET',
  url: '/search',
  params: {
    term: 'foobar',
  },
});

@shuding
Copy link
Member

shuding commented Nov 21, 2019

It will work :)

@Svish
Copy link
Contributor Author

Svish commented Nov 21, 2019

@quietshu Quick question... does config have any effect on whether useSWR decides to revalidate? I.e. do I need to useMemo if the config might not be the same object every time (even though it has the same contents), or would that be unnecessary?

@Svish Svish mentioned this issue Nov 21, 2019
@shuding
Copy link
Member

shuding commented Nov 22, 2019

@Svish nope, config change doesn't trigger revalidation (so you don't need to wrap it with useMemo, you can just change it). The only exception is config.refreshInterval. If that changes, SWR will adjust the polling interval.

@shuding shuding closed this as completed Nov 27, 2019
@o-alexandrov
Copy link

o-alexandrov commented Dec 2, 2019

@Svish
Thank you for the example.
In case anyone interested, a typed version of this example:

import axios, { AxiosError, AxiosRequestConfig, AxiosResponse } from "axios"
import useSWR, { ConfigInterface } from "swr"

export const useSWRAxios = <Data extends {}>(
  request: Omit<AxiosRequestConfig, "baseURL" | "method" | "data">,
  config?: ConfigInterface,
) => {
  const requestModified: AxiosRequestConfig = {
    ...request,
    method: `GET`,
  }
  const configModified: ConfigInterface = {
    ...config,
    // global customizations
  }
  /**
   * Axios has a wrapper object around data => filter response
   */
  const { data: response, ...responseUseSWR } = useSWR<
    AxiosResponse<Data>,
    AxiosError
  >(
    JSON.stringify(requestModified),
    async () => axios(requestModified),
    configModified,
  )
  const { data, ...responseAxios } = response || {}
  return { ...responseUseSWR, responseAxios, data }
}

@Svish
Copy link
Contributor Author

Svish commented Dec 2, 2019

@o-alexandrov If you check out the pr i added for this, I did add one for typescript 😉

https://github.com/zeit/swr/blob/master/examples/axios-typescript/libs/useRequest.ts

@bravo-kernel
Copy link

As a noob end-user the useRequest axios example just works, awesome. I do have a feeling that some swr features like trigger no longer "just work". If confirmed, I could add a small disclaimer to the examples.

@corysimmons
Copy link

corysimmons commented Jun 30, 2020

How do you folks handle updating the cache with this useRequest helper? Seems like an anti-pattern whenever there is already a good pattern that accepts any fetch implementation.

Sorry, not trying to dump on the helper, I'm just worried this Issue will cause people to reach for the useRequest implementation when they inevitably Google for "swr axios" (like I did) and completely overlook one of SWR's best features: cache.

I'm new to SWR, so maybe I'm missing something. If so, I'd appreciate anyone educating me. 🙇

@rohithroshan-pss
Copy link

// useRequest.js
export default function useRequest(request, config) {
const { data: response, error, isValidating, revalidate } = useSWR(
JSON.stringify(request),
() => axios(request),
config
);

return {
data: response && response.data,
response,
error,
isValidating,
revalidate,
};
}
const { data } = useRequest({
baseURL: 'https://api.example.com',
withCredentials: true,
method: 'GET',
url: '/search',
params: {
term: 'foobar',
},
});

give ex for post method @Svish ,please help . I am struck

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation question
Projects
None yet
Development

No branches or pull requests

6 participants