Closed RoboVij closed 2 years ago
In order to rerender or fire watch method you must pass new array or new object, so what you wrote is working as expected as clearing an array (e.g. with splice) modifies original array. Read more in docs https://stenciljs.com/docs/reactive-data
@MarkChrisLevy is correct here. A new array must be returned:
Instead, non-mutable array operators should be used as they return a copy of a new array. These include map() and filter(), and the ES6 spread operator syntax.
(source)
The reason for this is in the name of efficiency. It's a much easier/faster check to see if a variable points to a different array entirely, than to see of the array itself has changed. That page of our docs could use some work though - I'm going to put an item in our backlog to try to clarify some things/update the contents.
@RoboVij Does that answer your question? If not, could you please post full reproduction to github the team could pull down? Thanks!
A small update. This is how my actual code looks like. It's in vue. So when the array is updated with elements i.e. when showItems1 or/and showItems2 is/are true, the @Watch() is being rerendered. When both showItems1 and showItems2 are false, my array has no elements in it so no rerendering.
For arrays, the standard mutable array operations such as push() and unshift() won't trigger a component update.
But I am using push() and it is working. Is it working because of the spread operator ...this.items1
? If yes, how do I make it work for the emptied array case? I can't use the spread operator then.
<parent-items
...
:collection.prop="items"
></parent-items>
computed: {
items() {
let list = [];
if (this.showItems1) {
list.push(...this.items1);
}
if (this.showItems2) {
list.push(...this.items2);
}
return list;
},
}
Hey @RoboVij,
To be able for us to really determine if this is a bug or not, can you please upload a minimal reproduction case for the team to pull down? While code snippets help provide some context, building out a reproduction case can help us answer questions like:
Specifically, any of these questions you may be able to help us answer beforehand would be much appreciated/expedite the process.
Thanks!
Thanks for the issue! This issue has been labeled as needs reproduction
. This label is added to issues that need a code reproduction.
Please reproduce this issue in an Stencil starter component library and provide a way for us to access it (GitHub repo, StackBlitz, etc). Without a reliable code reproduction, it is unlikely we will be able to resolve the issue, leading to it being closed.
If you have already provided a code snippet and are seeing this message, it is likely that the code snippet was not enough for our team to reproduce the issue.
For a guide on how to create a good reproduction, see our Contributing Guide.
@rwaskiewicz How do I reproduce this? Because, first I need to create the plugin project with Stencil and store it somewhere. Then, I need to install this plugin in a Vue project. So do I need to create two projects and where do I store the plugin built by Stencil to be able to install it in Vue? (Currently we're storing it in our private npm, so I can't share that)
My main question is what I wrote in the previous code snippet supposed to work i.e. rerender @Watch() by emptying array like that? Is the code in computed
providing a new array or modifying the original array? (I guess it's more of a Vue question than Stencil's. But maybe you've an idea)
Hey @RoboVij,
My main question is what I wrote in the previous code snippet supposed to work i.e. rerender @watch() by emptying array like that?
I'm not sure - that's the reason we ask for a code reproduction case. It allows us to see the whole picture, rather than trying to piece together bits of code snippets when trying to determine if this is a bug or not.
How do I reproduce this? Because, first I need to create the plugin project with Stencil and store it somewhere. Then, I need to install this plugin in a Vue project. So do I need to create two projects and where do I store the plugin built by Stencil to be able to install it in Vue?
That sounds like a good process! I would start with recreating a new Stencil project with npm init stencil@latest component my-library
and trying to see if you see the same behavior in the sample project. If it's reproducible, that can be pushed up to GitHub/Stackblitz/etc. for someone on the team to take a look.
If that doesn't reproduce it, then yes, you'd need to wrap your components using the Vue wrapper and create a demo that uses it and upload that as well. Because that does entail extra work, it's beneficial to see if you can replicate this in just Stencil first.
Currently we're storing it in our private npm, so I can't share that
Totally understandable! We don't want to encourage that anyone share private code
@rwaskiewicz It works properly within the Stencil project, the @Watch() rerenders in the empty array case. So I tried publishing to npm to test it in the Vue project. This is my first time publishing to npm. So I'm not sure what I'm doing wrong, but I couldn't test it because of this error:
[Vue warn]: Unknown custom element: <my-component> - did you register the component correctly? For recursive components, make sure to provide the "name" option.
Stencil project: https://github.com/RoboVij/stencil-tester-watch npm package: https://www.npmjs.com/package/stencil-tester-watch Vue Project: https://github.com/RoboVij/stencil-test
@RoboVij It does look like your Vue application doesn't know about <my-component>
. To see how to wire that up, please see our integration guide with Vue.
Looking at your Stencil project, there exists at least one code path where the original array is reused (and won't cause a rerender). In onTesterChanged
:
// note: I added additional newlines here to point different things out
const parsed = typeof arr === 'string'
?
arr.trim() ? JSON.parse(arr) : []
: arr; // this uses the original array. which won't cause a rerender
const source = Array.isArray(parsed)
?
parsed // if `arr` above was an array, we reuse it
: parsed ? [parsed] : [];
I would recommend reworking that line I pointed out to generate a new array.
With that in mind, I'm unable to reproduce an issue in Stencil itself with this example. I've added a ticket to our backlog to update the documentation to make it a little clearer.
I'm going to leave this issue open for a few more days. If you're able to get the reproduction case working in that time, we can take a closer look.
I'm going to close this issue due to lack of reproduction case. If this is still an issue, please feel free to create a new issue with a minimal reproduction URL for the team to pull down and take a look at. Thanks!
Prerequisites
Stencil Version
2.11.0
Current Behavior
I'm passing down an array of objects as prop into a stencil built component.
When I change the
collection
array the @Watch() decorator is detecting the prop, even if the array has 1000 to 10000 objects in it. But it's not detecting when I make the array empty from whatever no. of objects in it. Is thi sexpected behaviour or what am I doing wrong?Inside the
parent-items.tsx
file in stencil:Type definition:
Expected Behavior
@Watch() decorator should detect the empty array.
Steps to Reproduce
Check the code samples.
Code Reproduction URL
--
Additional Information
No response