justin-schroeder / arrow-js

Reactivity without the framework

Home Page:https://arrow-js.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Binding reactively to array length

Clonkex opened this issue · comments

Say I have this:

const selectedProductIds = reactive([]);
return html`
    <div>
        <span>Selected products: ${() => selectedProductIds.length}/${productCount}</span>
    </div>

    ...

    <input type="checkbox" ${selectedProductIds.includes(productData.internalId) ? 'checked' : ''} @input="${e => {
        if (e.target.checked) {
            if (!selectedProductIds.includes(productData.internalId)) {
                selectedProductIds.push(productData.internalId);
            }
        } else {
            if (selectedProductIds.includes(productData.internalId)) {
                selectedProductIds.splice(selectedProductIds.indexOf(productData.internalId), 1);
            }
        }
        selectedProductIds.length = selectedProductIds.length + 1; // <----- how can I not have to do this?
        selectedProductIds.length = selectedProductIds.length - 1;
    }}"/>

How can I avoid having to do the jankiness of those last two lines? If I only push to the array or splice from it, the reactive length binding doesn't update.

I think the issue here is that you’re reactive data is the array itself instead of a property of the array. Consider your "reactive" more like a store, you want to set data on properties of your reactive rather then itself. So:

const store = reactive({ selectedProductIds: [] });
// ...
html`<span>Selected products: ${() => store.selectedProductIds.length}/${productCount}</span>`

These changes propagated throughout the code should get you sorted.

Ah I nearly just tried that, but I figured arrays are objects and I'm not assigning the array at any point so it should be fine.

Wrapping it in another object does indeed fix the issue, thanks!