Closed AmyBlankenship closed 2 years ago
Sorry, not sure I'm following the situation here. Can you put together a CodeSandbox that shows this happening, particularly with some example TS types?
I don't understand what would need to "happen", since the signature of updateQueryData is presumably something you know. It returns void, so even if I tried to return [...draft, ...patchInfo.model], there is nothing that will pick it up and do anything with it? Is there some secret overload that's not accounted for in the typing?
I'm more asking to see what your app code looks like so I can better understand what you're trying to accomplish.
Like, you've got this reduce()
there, but I don't know what the incoming data is, what the existing data is, how it needs to be applied, etc.
The other thing is that I believe the callback you pass into updateQueryData
ends up being passed straight to Immer. So, you should be able to either mutate draft
, or return a new value, as usual with Immer.
The partial snippet in the first comment is also still confusing me - I think you left out too much context there, which is also why I'm asking for the sandbox.
So let's say the existing data is
{id: 1
name: 'Frank'
job: 'Bricklayer'
}
And let's say that sometimes patchInfo.model is
{
id: 1
name: 'Jill',
}
other times it might be
{
id: 1
job: 'Astrophysicist',
}
etc.
Because it looks like you have to mutate the draft instead of returning a new value (and all of the examples I have looked at show that--none of them show returning a value), then it seems like you have no choice but to mutate the Immer draft.
If this is not the case, I guess that would be in the Immer docs, but TBH I feel like the chief value of immutability is in getting you to think in immutables, so a library that makes things immutable but encourages you to think about it as if it's mutable is something I don't have a huge interest in learning.
Cool, just tried this and actually it does work even though I thought it would not from looking at the docs. Thanks!
Also, I apologize for the typo where I did [...draft, ...patchInfo.model] instead of {...draft, ...patchInfo.model}. I can see now why that would be confusing.
Yeah, the array-vs-object-spread thing was kinda throwing me off :)
But yes, in general, Immer has always let you either mutate the draft, or separately create and return a new immutably updated object yourself:
Inside updateQueryData
, the internal logic is:
if ('data' in currentState) {
if (isDraftable(currentState.data)) {
const [, patches, inversePatches] = produceWithPatches(
currentState.data,
updateRecipe
)
ret.patches.push(...patches)
ret.inversePatches.push(...inversePatches)
} else {
const value = updateRecipe(currentState.data)
ret.patches.push({ op: 'replace', path: [], value })
ret.inversePatches.push({
op: 'replace',
path: [],
value: currentState.data,
})
}
}
so if cacheEntry.data
appears to be an object or array that can be mutated, we call Immer's produceWithPatches()
and just immediately pass in your callback to do the work. So, the usual "mutate or return" rule applies.
Thanks :). As I said, I don't really know what's usual for Immer. At some point I plan to write an article about my experiences with RTK Query, so this will all come to something that might be useful to someone. But my backlog is quite long.
BTW, you seem to be very quick answering questions. Do you have availability and would you be looking for work?
Hah, I'm full time at https://replay.io, and very happy there :)
I just happen to be obsessive about refreshing unread notifications pay close attention to reported issues for both day job and Redux stuff.
OK, my boss asked me to ask :-D
Related reading recommendation: Writing Reducers with Immer - also applies to updateQueryData
:)
We have patch endpoints that just take the properties to be patched. So the full object might look like:
In most cases, I don't want to invalidate the tag for this, because it's a "parent", and just changing a prop on it shouldn't cause the whole tree to reload. So I'm doing optimistic updates, and only invalidating the tag if something happens that needs everything to reload. The immer architecture is forcing me to do this
instead of
[...draft, ...patchInfo.model]
But the signature of updateQueryData tells me I don't have any obvious way to use the simpler syntax.