swr: Multiple Arguments with object in render breaks cache
Hi,
It seems that multiple arguments with object in render breaks cache :
// Make sure objects are stable
const params = useMemo(() => ({ id }), [id])
useSWR(['/api/user', params], query)
If you follow this use case :
id = 1 --> id = 2 --> id = 1
The second id = 1 doesn’t have the same key in cache as the first (because params doesn’t have the same ref)
Reproductible codesandbox : https://codesandbox.io/s/swr-multiple-arguments-no-cache-mfssd
The only way I found to preserve cache is to stringify in memo and parse in fetcher (https://codesandbox.io/s/swr-multiple-arguments-cache-p8iwy)
const params = useMemo(() => JSON.stringify({ id }), [id])
any better idea ?
Thanks !
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Reactions: 3
- Comments: 16 (5 by maintainers)
🎉 Added support for key serialization in #1429 and released as
1.1.0-beta.0, you don’t needuseMemoanymore. CC: @nandorojoYes this is indeed a problem. In our real world use cases, we’re using it like this:
Because
useris a globally shared object, the cache key of the second query will always be stable. For use cases like query params, I will still suggest passing primitive values as args directly (will update documentation as well):We have some discussions here https://github.com/zeit/swr/pull/145#discussion_r350064725.
We now have an example on how to add key-serialization with SWR v1 Middleware: Serialize Object Keys. This can solve the original issue in this thread, maybe someone can publish it as a handy library?
Deep comparison would be a great addition, but I’m still having concerns about the performance (as well as serialization). Imaging a huge list with
useSWRhooks inside, each re-render needs to run a synchronized deep comparison. We need to get some benchmarking for this.My current working solution :
@nandorojo Yeah we could provide an option to support custom key serialization. There’re probably some more efficient JSON stringify implementations, but I’m not sure about type safety…
react-queryprovides deep-equal support for items in an array key. Is this the type of thing we could implement? Maybe a customdidKeyChangefunction could live in the config?I know that deep-equal checks aren’t ideal, and it is slow to run on every render. However, for use-cases with large objects as a key, a plain array key has bad type safety. For instance, I have an algolia search wrapper with swr.
The SWR key takes all of these fields, so I currently use
JSON.stringifyPassing each options as primitives to an array isn’t great. However, stringifying it also isn’t very good, since I have to then
JSON.parseinside of thefetcherand cast the types to it:Is there a type-safe solution that is more efficient than
JSON.stringify?@shuding I’m also coming across this problem. Is there any newer recommended solution for this? Our use case is essentially making a generic fetching function which needs to be able to accept flexible variables, so
passing primitive values as args directlydoesn’t fit the use-case.Maybe useSWR should deep-compare the input, just like it deep compares output? (possibly could be a config option?) Thinking that this would solve the issue you mentioned in your comment on the axios example linked above.