-
-
Notifications
You must be signed in to change notification settings - Fork 8.7k
Triggering a ref passed as a prop does not cause an update in the nested component #7614
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
Comments
as a workaround <Canvas :data='[...data]' /> |
Hi @edison1105, thanks for the quick response! Your workaround is a good one for the specific example I gave in the issue, but has performance implications that prevent it from being a workaround in my actual use case, where the data is a large Uint8Array representing the ImageData of a canvas. One alternative workaround would be to wrap the data array in a new plain object each time, but that would still require creating a new object for each update. I wonder if there’s a workaround that doesn’t require an allocation each time the image data changes (which can be as often as every frame)? |
@yurivish |
I've seen variations on this theme a few times on Vue Land. I added a note about it a few weeks ago in the docs repo, vuejs/docs#849 (comment), as it's something we might want to consider documenting. While I can understand why people find it counterintuitive, I don't think there's a bug here. It's effectively like calling
Maybe there is some magical way to make this work, but I suspect it'd need a new API to do it, to avoid breaking changes to the existing APIs. Ultimately we might just need to document this better.
The parent is re-rendering, which updates the props on the child. But the props on the child are considered equal from a |
I agree with @skirtles-code When working with nonreactive data, it's better to then work with immutable data as @edison1105 suggested. |
Thank you for the great explanation, @skirtles-code. The issue you linked containing explanations of problems with reactivity is also very useful. I think my mistake here was actually in not understanding how props are passed – I knew that that triggering a ref without changing its value would cause re-evaluation only "one level" down – ie. any direct dependents would be re-evaluated, with the usual rules being followed beyond that – but thought that I could pass the Here's an example I made in the SFC playground that clarified things for me. It explores the various options for passing a It looks like what's happening is that Vue will unwrap any
So the only way of giving the child component access to the By the way, thanks for your work on the Vue docs – they're really good and a big part of why I got interested in exploring Vue in the first place. |
@yurivish The Playground you linked is slightly misleading. Both the parent and child templates will unwrap refs, so it isn't immediately clear in each example whether the unwrapping is occurring in the parent or the child. The process of passing a prop doesn't directly unwrap anything. Top-level refs are unwrapped automatically whenever they are used in the template. So if a ref is wrapped in a plain object it will not be unwrapped, Playground example.
See also https://vuejs.org/guide/essentials/reactivity-fundamentals.html#ref-unwrapping-in-templates. |
I was using the output of the handy JS inspector in the playground to see where the unwrapping was happening: return (_ctx, _cache) => {
return (_openBlock(), _createBlock(Canvas, {
data: data.value,
getData: getData,
inlineGetData: () => data.value,
wrappedData: wrappedData,
inlineWrappedData: { data: data.value },
renamedData: _unref(renamedData)
}, null, 8 /* PROPS */, ["data", "inlineGetData", "inlineWrappedData", "renamedData"]))
}
} Thank you for the corrections and clarifications (and the example)! Learning a lot today. :) |
Uh oh!
There was an error while loading. Please reload this page.
Vue version
3.2.45
Link to minimal reproduction
https://sfc.vuejs.org/#eNqlU01v2zAM/SuED7WDOlI/tku+0GLYYbdhWE91gaoxE7uxJUGiYxSB//uoOB9uV+yyiyHxke9RfPQuurdWbBuMJtHML11pCTxSYxeZLmtrHMEOfKGqyrS/cJUCuXK9Rrc/t4qWxffVCpeUgtEPujaNJsyhg5UzNcTMG594vim9Vf6ACNlfg3ScUaYzvTTaE+SKFMwHkonGFh5KTbc3986pt+R6NJpmGuBYwRC6rapCFdKPwy1JRjBfwI6Zqc9TznFK4BeMNxg4OPZ49XR5Gc4hy1QoKrNOhBAMjUL4/OAk1HKsS+H66ooPgycf5JYVKndq4djZiHMzLSX8LkoPrtEe2gI1PJ+5n4GRUm/NBvMUXhoCKnDf7L7QOmPBKu95uGSOo8wNeh0Hw7AO4da4zb7OqxrZnTeR6YFHxx4H7zxPI/Q4k/0GsPd8IaxtpQj5BjCzi4uKprwsF2uawt6JwESoyU9gt+tDIrjbz0m8mlIncQrxCLpuJsNGMc+h9UnImcfhG4NkaCZPelEa9SszrpUVr95oXk42ki0/AD6LWDNEQoxXKNyzqCCyfiJlo+1mLZamlneMSR44lTWOc1Pf3Yob8eWrzEtPw7hAX49fnGk9OlbMonRALjm4RTd2qHN06P4p9iH3neAH7C/RoNnxfvEAzn/HJz9mjqtS40/eCZ889jN8em/fp+b1nP/j39Ck7g+CjnZe
Steps to reproduce
Observe the output – the two lines should be identical, but they are not.
What is expected?
data
is ashallowRef
holding an array.There is a
setInterval
that updates an array element, then triggers thedata
shallowRef.The two lines of output should be the same – the first is the direct output of the App template and the second is the output of a nested Canvas component.
What is actually happening?
For some reason, despite the
triggerRef
calls, the reactivity does not propagate to the Canvas component instance.System Info
No response
Any additional comments?
Curiously, if I pass the prop as
:data='[data]'
instead of:data='data'
, then the two stay in sync.I think this means that triggerRef causes the data prop to re-evaluate, and since each evaluation returns a new array object (
[data]
) this causes the Canvas component to be re-rendered.But I think that data changing should be enough to cause the Canvas component to re-render, and it is puzzling why it doesn't.
The text was updated successfully, but these errors were encountered: