vincent15000's avatar

In which cases could the DOM not be updated whereas the datas are updated ?

Hello,

It's a Laravel 11 / VueJS 3 application.

I have explored my own code, all datas are reactive (ref, computed).

The datas are stored in a pinia store and initially loaded via an API request to the backend.

When datas are updated in the database, the backend triggers an event to the websocket and I listen to these events in the frontend. The websocket sends only the updated datas and I dynamically update the array in the store.

console.log() in the websocket listener shows that the datas are updated, but the DOM isn't refreshed.

Without giving any specific code example (for the moment), in which cases could the DOM not be updated whereas datas are updated ?

Thanks for your help.

V

0 likes
7 replies
MohamedTammam's avatar
Level 51
  1. The value from pinia is passed incorrectly to the component.
  2. Updating the array in un-reactive way.
1 like
vincent15000's avatar

@MohamedTammam What do you mean by passing the value from pinia to the component ?

In the component, I use the store and I access to the datas via myStore.books.

vincent15000's avatar

@MohamedTammam No, each time an event is triggered, the listener in the frontend executes this code.

dashboardStore.endpoints.splice(endpointToRefreshIndex, 1, data.endpoint);

And in the dashboard store, endpoints is a ref.

And a similar code for another page works fine.

vincent15000's avatar

@MohamedTammam Here is the code flow.

// 1 - Page loading

onMounted(async () => {
    await dashboardStore.loadEndpoints();
});

// 2 - Store

async function loadEndpoints() {
    const res = await dashboardService.endpoints();

    if (res.status === 200) {
        endpoints.value = res.data.data;
    }
}

// 3 - In the component

// Preparation of the datas to be displayed (necessarily to have a specific visual.

const endpoints = computed(() => {
    return dashboardStore.endpoints.filter(endpoint => endpoint.active_connection.branch_id === (props.branch ? props.branch.id : null));
});

...

const networks = computed(() => {
    return dashboardStore.networks.filter(network => network.branch_id === (props.branch ? props.branch.id : null));
});

...

const arrayOfItems = computed(() => {
    const items = [];

    endpoints.value.forEach(endpoint => {
        items.push({
            component: EndpointComponent,
            type: 'endpoint',
            object: endpoint,
            key: 'endpoint-'+endpoint.id+'-state-'+endpoint.active_connection.state.id,
        });
    });

    networks.value.forEach(network => {
        items.push({
            component: NetworkComponent,
            type: 'network',
            object: network,
            key: network.id,
        });
    });

    return items;
});

...

const structuredArrayOfItemsInRows = computed(() => {
    const rowsOfItems = [];

    const itemsNumber = arrayOfItems.value.length;

    if (itemsNumber > 0) {
        let hexagonWidth = 200;

        let numberOfDevicesPerOddRow = Math.floor((clientWidth.value + 8) / (hexagonWidth + 8));
        if (numberOfDevicesPerOddRow < 1) {
            numberOfDevicesPerOddRow = 1;
        }

        let numberOfDevicesPerEvenRow = Math.floor((clientWidth.value + 8 - 104) / (hexagonWidth + 8));
        if (numberOfDevicesPerEvenRow < 1) {
            numberOfDevicesPerEvenRow = 1;
        }

        let remainingNumber = itemsNumber;
        let odd = true;
        let index = 0;
        while (remainingNumber > 0) {
            let number = 0;
            if (odd) {
                number = remainingNumber < numberOfDevicesPerOddRow ? remainingNumber : numberOfDevicesPerOddRow;
            } else {
                number = remainingNumber < numberOfDevicesPerEvenRow ? remainingNumber : numberOfDevicesPerEvenRow;
            }

            const itemsToPush = arrayOfItems.value.filter(function (item, itemIndex) {
                return itemIndex >= index && itemIndex < index + number;
            });

            const row = [];

            itemsToPush.forEach(item => {
                row.push(item);
            });

            rowsOfItems.push(row);

            index = index + number;
            remainingNumber = remainingNumber - number;
            odd = !odd;
        }
    }

    return rowsOfItems;
});

// 4 - And the view of the component

<div
    v-for="(rowOfItems, rowIndex) in structuredArrayOfItemsInRows"
    :key="'row-'+rowIndex"
    class="flex gap-2"
    :class="{ 'ml-[104px]': rowIndex % 2 !== 0, '-mt-[57.7350px]': rowIndex > 0 }"
>
    <component
        v-for="(item, itemIndex) in rowOfItems"
        :key="JSON.stringify(item.object)"
        :is="item.component"
        :item="item.object"
        :data-id="item.object.id"
    ></component>
</div>

// 5 - When an event is triggered, this code is executed

websocketStore.userChannel.bind('endpoint.updated', (data) => {
    const endpointToRefreshIndex = dashboardStore.endpoints.findIndex((endpoint) => endpoint.id === data.endpoint.id);

    if (endpointToRefreshIndex >= 0) {
        dashboardStore.endpoints.splice(endpointToRefreshIndex, 1, data.endpoint);

        console.log('Endpoint updated');
    } else {
        dashboardStore.endpoints.push(data.endpoint);

        console.log('Endpoint created');
    }
});

Please or to participate in this conversation.