3.0.0-rc.8
https://codesandbox.io/s/bold-violet-rsjis
Run the structured clone algorithm on a reactive object.
The object is cloned (losing the proxy in the process).
A DataCloneError is thrown
Originally encountered this bug in an Electron application, where the structured clone algorithm is used for any data passed between windows.
Create a copy instead, HistoryState does not accept all kind of values
The whatwg#structuredserializeinternal specification says:
if IsCallable(value) is true, then throw a "DataCloneError" DOMException.
The Proxy Object contains [[call]] as an internal slot, so I don鈥檛 think it鈥檚 Vue鈥檚 issue.
Create a copy instead
Since the structured clone algorithm is a standardised algorithm to copy Javascript objects, which is more powerful than JSON.parse(JSON.stringify(...)), I don't quite understand how I would simply "create a copy" (with more complex objects like a Map).
Again, my usecase isn't really HistoryState, but rather a large Electron application where all data going to and from the Node backend have to go through SCA. In the frontend, most of that data ends up in vuex, so it all gets turned into reactive objects.
The Proxy Object contains [[call]] as an internal slot, so I don鈥檛 think it鈥檚 Vue鈥檚 issue.
If Proxies just can't be made to work with the SCA, then I think Vue should provide a deep variant of toRaw. Otherwise, as far as I can tell, there's currently no way to get a plain JS object back from a reactive object containing other reactive objects.
I don't quite understand how I would simply "create a copy" (with more complex objects like a Map).
You cannot pass a Map to HistoryState, you will have to serialize it yourself anyway
If Proxies just can't be made to work with the SCA, then I think Vue should provide a deep variant of toRaw. Otherwise, as far as I can tell, there's currently no way to get a plain JS object back from a reactive object containing other reactive objects.
Yes, there is:
const s = reactive({})
history.pushState({ ...s })
If you have any non-serializable data like a Map, you will have to serialize it first
You cannot pass a Map to HistoryState, you will have to serialize it yourself anyway
As stated a couple of times, this is not about HistoryState (although that does to use SCA and support Maps, at least in some modern browsers: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm)
Yes, there is:
I don't see how that works for nested objects.
If you have any non-serializable data like a Map, you will have to serialize it first
Not to JSON, but with the SCA, they can be serialised.
I don't see how that works for nested objects.
Just use toRaw():
history.pushState(toRaw(s))
Just use toRaw():
I tried that, it only seems be a shallow toRaw: https://codesandbox.io/s/distracted-keldysh-00h8c
A deepToRaw would be a good fix/workaround IMHO :) (or probably for consistency, toRaw and shallowToRaw)
@posva Maybe we need to reopen this? I think it's a valid use case 馃.
Technically deepToRaw is not possible, because in the example of
const s = reactive({
foo: reactive({})
})
The raw version of s does contain foo as a reactive object. If you want s.foo to be a raw object as well, you must clone raw s - but that is no longer the actual raw s. Which means it's essentially a deep clone. In this case, you probably want to just run it through a helper like _.cloneDeep (which is loosely based on SCA).
Just re-read the spec and in item 23 of the SCA it explicitly states SCA does not accept Proxy objects. So yes a deep clone is pretty much required in this case. It actually is not related to the [[Call]] slot.
Ah, see it~
Most helpful comment
Technically
deepToRawis not possible, because in the example ofThe raw version of
sdoes containfooas a reactive object. If you wants.footo be a raw object as well, you must clone raws- but that is no longer the actual raws. Which means it's essentially a deep clone. In this case, you probably want to just run it through a helper like_.cloneDeep(which is loosely based on SCA).