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

how to use post method and pass params in swr? #93

Closed
nai6514531 opened this issue Nov 7, 2019 · 21 comments
Closed

how to use post method and pass params in swr? #93

nai6514531 opened this issue Nov 7, 2019 · 21 comments

Comments

@nai6514531
Copy link

No description provided.

@monman2l
Copy link

monman2l commented Nov 7, 2019

const fetcher = params => url => post(url, params)
const { data, error } = useSWR('/api/user', fetcher({key: val}))

This way?

@sergiodxa
Copy link
Contributor

SWR is more intended to get data, not update it, usually you have another function to update and after it you will run mutate to update the cache and trigger a revalidation (SWR will fetch it again)

@sergiodxa
Copy link
Contributor

This example https://github.com/zeit/swr/tree/master/examples/optimistic-ui does something similar, update and then revalidate

@shuding
Copy link
Member

shuding commented Nov 7, 2019

UPDATE 2022.6:

SWR 2.0 beta now has a dedicated API for one-off requests such as POST. Docs and examples can be found here:

https://github.com/vercel/swr/releases/tag/2.0.0-beta.0

It also supports many good things such as cache population, error rollback and race condition prevention.


Original answer:

function App() {
  const { data } = useSWR('/api/data', fetch) // <--------------GET

  return <>
    {data}
    <button onClick={() => {
      fetch('/api/data', { method: 'POST', body: ... })  // <---POST
    }}>update data</button>
  </>
}

You can just use fetch for POST requests. I don't see the benefit of allowing POST in SWR.
And most importantly, most of the great features will be gone with POST (because it's not a "pure" action like GET, which is perfect for fetch-as-you-render):

  • stale-while-revalidate (SWR)
  • focus revalidate / polling
  • automatically request deduplication
  • caching
  • ...

But speaking of revalidation/mutation, it's still a thing for allowing POST together with SWR. Currently we need to do this:

mutate('/api/data', newData, false) // local mutate without revalidation
await sendPost('/api/data', newData) // POST request
trigger('/api/data') // revalidate

Maybe we can simplify it to something like:

mutate('/api/data', newData, sendPost)

which will do the exact same thing as above.

@shuding shuding mentioned this issue Nov 8, 2019
@nicolaslohrer
Copy link

Maybe it'd be worth checking out react-query's useMutation() hook for reference as well.

@iammarkps
Copy link

I have a use case with firebase onCall function(which it's method is POST). Because it supports authentication by default, I have to use this workaround.

import firebase from '../lib/firebase'

export const fetchSubmissionData = async (id: string) => {
  const getSubmission = firebase
    .app()
    .functions('asia-east2')
    .httpsCallable('getDetailedSubmissionData')

  return await getSubmission({ submission_id: id })
}

Then I can use

 const { data } = useSWR(`${id}`, fetchSubmissionData)

My function is onCall because it needs to verify user before sending back data.

Any idea on improving this? @quietshu

@shuding
Copy link
Member

shuding commented Nov 9, 2019

@iammarkps can you show me a POST example you have without using SWR?

@iammarkps
Copy link

I always use it that way. But I'm just curious that, can I have only 1 global function to use firebase callable function?

Now I have to implement 3 different functions with same logic.

https://github.com/programming-in-th/programming.in.th/blob/master/src/utils/fetcher.ts

Because firebase callable function receives 2 args, not 1 like normal GET request(Just url of API).
Can SWR pass 2 arguments to functions?

PS.Pardon my bad english

@iammarkps
Copy link

I've used to do this when I was using redux (It's POST method).

https://github.com/programming-in-th/programming.in.th/blob/83ff9a23648e9ece55f8abeb555292da28908dac/src/redux/actions/submission.ts#L24

and this for normal data fetching (Still POST method)

https://github.com/programming-in-th/programming.in.th/blob/83ff9a23648e9ece55f8abeb555292da28908dac/src/redux/actions/task.ts#L34

But now I've converted it to normal http GET not firebase callable anymore.

https://github.com/programming-in-th/cloud_functions/blob/master/functions/src/tasks.ts#L4

So it works perfectly with SWR.

But I can't convert this to http GET, because I have to check user right to access the code in line 187. So I need to depend on firebase request context. @quietshu

@iammarkps
Copy link

I want to do this


export const fetchFromFirebase = async (type: string, param?: Object) => {
    const get = firebase
    .app()
    .functions('asia-east2')
    .httpsCallable(type)

  return await get(param)
}

@shuding
Copy link
Member

shuding commented Nov 9, 2019

@iammarkps thanks for elaborating! 👍

Now I can understand your use case, it makes perfect sense.

Can SWR pass 2 arguments to functions?

And yes! This feature will solve the problem: #98

We just shipped it to swr@0.1.9 and you can use it but the documentation is not yet updated. Ideally your code will be:

useSWR([type, param], fetchFromFirebase)

But keep in mind it compares arguments shallowly, so keep in mind to memorize the object:

const param = useMemo(() => ({ submission_id: id }), [id])
useSWR(['getDetailedSubmissionData', param], fetchFromFirebase)

iammarkps added a commit to programming-in-th/programming.in.th that referenced this issue Nov 9, 2019
@iammarkps
Copy link

@quietshu Thank you! I've just improved it with your suggestion in this commit

@shuding
Copy link
Member

shuding commented Nov 9, 2019

@iammarkps looks great!

@nai6514531 nai6514531 changed the title hot to use post method and pass params in swr? how to use post method and pass params in swr? Nov 11, 2019
@pedronauck
Copy link

pedronauck commented Nov 14, 2019

So, this should be work in the newest version (dependent data and multiple params):

const { data: user } = useSWR('/api/user')
const params = useMemo(() => {
  return { username: user && user.username }
}, [user])

const profile = useSWR(() => ['/api/profile', params])

Because I'm trying this and I'm getting an infinite loop always 😕

@shuding
Copy link
Member

shuding commented Nov 14, 2019

@pedronauck oh that's because you're using a function which returns an array here:

const profile = useSWR(() => ['/api/profile', params])

This case is not yet covered (thanks for reporting!), for now you can just use an array:

const profile = useSWR(['/api/profile', params])

@DeepakKapiswe
Copy link

I Used like this and it worked for me, please let me know If I’m missing something

let url = 'some url here';

export default function ComponentName  (props) {
  const fetcher = (...args) => fetch(url, {
    method: 'post',
    headers: {
      "Content-Type": "application/json"
    },
    body: JSON.stringify(props.payload)
  }).then(res => res.json())

  const { data, error} = useSWR(url, fetcher, { suspense: true });

@theweiweiway
Copy link

theweiweiway commented Apr 1, 2020

Hi! Great library, I had a quick question:

const profile = useSWR(() => ['/api/profile', params])

Right now, it's fetching whenever any attribute of params changes. Is there a way for me to programatically make it fetch with updated params only when a specific attribute of params changes?

Thanks

@sergiodxa
Copy link
Contributor

You need to pass every attribute inside params as different elements of the array.

@yufengwang
Copy link

mark

@eric-burel
Copy link

Answers here are assuming that POST = data mutation
However POST is legitimately needed when doing list filtering that will explode the URL limitation of GET requests.

Multiple arguments help a lot here, the second argument can be "fetch" call options: https://swr.vercel.app/docs/arguments#multiple-arguments

@Panjo9
Copy link

Panjo9 commented May 16, 2024

well, this works for me:

const fetcher = async (api, data) => {
  try {
    const response = await axios.post(api, data);
    return response.data;
  } catch (error) {
    console.error('Error', error);
  }
};

export default function useCustomHook({ data }) {
  const {
    data: dataHook ,
    error,
    isLoading,
  } = useFetchSWR([api, { data  }], ([api, data]) => fetcher(api, data));

  return { dataHook } ;
}

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

No branches or pull requests