Closed Svish closed 4 years ago
Just tested replacing ...returned
with isValidating, error, revalidate
, which does make it work again. But I'm guessing this will also "undo" the re-render reduction you guys added in #186?
Is there a way I can write this useSWR
wrapper so it doesn't "break" this re-render reduction?
export default function useRequest(request, { initialData, ...config } = {}) {
const { data: response, isValidating, error, revalidate } = useSWR(
request && JSON.stringify(request),
() => axios(request),
{
...config,
initialData: initialData && {
status: 200,
statusText: 'InitialData',
headers: {},
data: initialData,
},
}
);
return {
isValidating,
error,
revalidate,
data: response && response.data,
response,
};
}
This looks like it's because useSWR
returns an object with getters on it... if you spread the return of that you lose the getters and the only property you'll get is revalidate
.
You can keep the getters by mutating the returned object to add your own properties:
export default function useRequest(request, { initialData, ...config } = {}) {
const returned = useSWR(
request && JSON.stringify(request),
() => axios(request),
{
...config,
initialData: initialData && {
status: 200,
statusText: 'InitialData',
headers: {},
data: initialData,
},
}
);
returned.response = returned.data
return returned
}
I'm not entirely sure if there's issues with this approach though.
It is rather unexpected though - I had the same issue but I was spreading the entire response of useSWR
so even data
was undefined for me.
@davecoates Yeah, your workaround seem to work for me too, but not sure if the result of it is different from what I had already. And no idea if either of our solutions break/keep the optimization they've implemented with these getters. 🤔
Yeah sorry for your case you'd want to add a getter on response
as well so that it doesn't prematurely access data
(my use case was just adding some extra options to the return that didn't need to read the values returned by useSWR)
eg. instead of returned.response = returned.data;
do:
Object.defineProperties(returned, {
response: {
get() {
return this.data;
}
},
});
Not sure that would work since I also replace data
with response.data
. I.e. I don't only add response
, but replace data
with something from the response
😕
What I'm trying to do here is that data
should be the actual data, since that's what's expected when using the hook, but since I'm wrapping axios, then data
returned from useSWR
is actually the axios response object. So I need to do a little bit of a switcheroo before I return things from my useRequest
wrapper. 🤔
Bumping this issue.
While following the steps in the readme and not wrapping the SWR request I am seeing isValidating
return undefined
.
Using version 0.1.16, downgrading to 0.1.15 fixes the issue.
When using the spread operator, getter
of the returned object can't be copied:
const { data, ...returned } = useSWR(...)
console.log(returned.isValidating) // will be undefined
Currently, we don't have a easy fix for it. I'll suggest not using ...
for now:
const swr = useSWR(...)
const { data } = swr
console.log(swr.isValidating) // will change over time
The getter improvement reduces unnecessary re-renders dramatically. I'll keep this issue open and look for a better solution, or add a notice on the documentation.
Can we add enumerable: true
in defineProperties
to make it present?
From version
0.1.16
theisValidating
flag doesn't seem to change anymore, it just stays at false, even when there is a request going on. Has the "API" of it changed after #186? Do I need to read it differently or something? Is it because I have wrappeduseSWR
in my own hook?Is there something in the way I get and pass on the returned values from
useSWR
here which is causing theisValidating
flag not to change? If so, how would you suggest I do it instead?Adding the following where I use my hook, just results in a single log message of
undefined
.