Subscribe on changes!

readonly(["a", "b", "c"]).includes() tracks dependencies even though array is nonreactive

avatar
Oct 27th 2020

Version

3.0.2

Reproduction link

https://codesandbox.io/s/vigorous-field-e0xxe?file=/src/App.vue

Steps to reproduce

readonly(["a", "b", "c"]) Collected by dependency

What is expected?

["a", "b", "c"] Should not be collected by dependency

What is actually happening?

["a", "b", "c"] Collected by dependency

avatar
Oct 27th 2020

You misunderstand what readonly does. This is expected behaviour. readonly still allows for values to be collected as dependencies - it only keep you from mutating the source objects through the procxy returned by readonly.

Maybe you are looking for markRaw() or one of the shallow*() APIs.

Edit: my analysis here was wrong, see below (https://github.com/vuejs/vue-next/issues/2493#issuecomment-717843604)

avatar
Oct 28th 2020

I'd like to ask why this design is so designed that indexes can't be collected by dependency, but by using lastIndexOf, indexof and includes. Shouldn't readonly behave consistently

avatar
Oct 28th 2020

Please be more specific and provide an example.

avatar
Oct 28th 2020

setup() { const readonlyState = readonly(["a", "b", "c"]); effect(() => { debugger; readonlyState.includes("a"); }); }, so
readonly(["a", "b", "c"]) Collected by dependency

if
setup() { const readonlyState = readonly(["a", "b", "c"]); effect(() => { debugger; readonlyState[0] }); }, readonly(["a", "b", "c"]) Should not be collected by dependency

Shouldn't readonly behave consistently

avatar
Oct 28th 2020

readonlyState.includes("a"); readonly(["a", "b", "c"]) Collected by dependency

readonlyState[0] readonly(["a", "b", "c"]) not be collected by dependency

Shouldn't readonly behave consistently

avatar
Oct 28th 2020

I'm still not sure what you are asking as your code doesn't contain any example of how different behaviour affects your use case.

However:

  • in the first example, using includes() makes the whole array a dependency, as well as each index, as any index could be "a".
  • in the second example, you access one specific index, and consequently only access to that specific index is collected as a dep.
avatar
Oct 28th 2020

I'd like to ask why this design is so designed readonly(["a", "b", "c"])
I mean, why don't you collect dependencies in both cases, or not

avatar
Oct 28th 2020

and readonlyState.includes ("a") to be collected dependency, readonlystate [0] will not be collected dependency , Any thoughts

avatar
Oct 28th 2020

We only collect the minimal dependencies necessary.

  1. in the first example, "a" could be anywhere in the array, so we have to collect the whole array as a dep.
  2. in the second example, we only need 1 dep for the first index of the array, because that's all that's ever read from the array.

I'm not sure how to make that clearer without an explanation of why you think we should collect more/something different.

avatar
Oct 28th 2020

Ah, now I get what you mean. I failed at reproducing it properly first with the snippet your provided.

Let's look into it, we might have an issue here.

avatar
Oct 28th 2020

You may have misunderstood the meaning

In the case of readonly(),

Why? readonlyState.includes ("a") to collect dependencies, readonlystate [0] will not collect dependencies Not consistent behavior

avatar
Oct 28th 2020

OK, thank you

avatar
Oct 28th 2020

So thanks for being adamant here, I was wrong.

readonly on a plain value should of course not track. I usually use it on reactive values only and didn't think about it enough.

So the problem seems to be here:

https://github.com/vuejs/vue-next/blob/0e5a3c47a7398dfd0107fccf9b615772dd01aa74/packages/reactivity/src/baseHandlers.ts#L85-L88

We should check for isReadonly here

avatar
Oct 28th 2020

Thanks for reporting, tracked it down and sent a PR.

Apologies for my initial stubborness.

avatar
Oct 29th 2020

Thank you for answering my questions