DocGashe
DocGashe

Reputation: 13

Vue Functional Components Re-render Entirely vs. Single SPA Component Re-render

I'm encountering an issue in my Vue application where the use of functional components within a table leads to entire re-renders of all cells when any cell's value changes, triggering a backend request and subsequently updating a list of cells based on the response. However, when I switch to using stateful template components for these cells, only the affected cell re-renders upon update.

Environment:

Problem Detail: My table component renders each cell as a separate component. The table includes column aggregators, and cell value changes initiate a backend request. The response dictates which cells to update. Using functional components for these cells results in the entire table re-rendering, but switching to standard stateful template components limits the re-render to only the changed cell.

// table.vue
<tr v-for="row in cells" :key="row[0].id">
 <TableCellHeader />
 <TableCell v-for="(cell, idx) in row.slice(1)"
  :key="row[0].data.id+'_'+idx"
  :cell="cell"
  :col-index="idx+1"
  :row-id="row[0].id"
  :disable="isDisabled(row[0], cell, idx+1)"
  @saved="save" />
</tr>
// tableCell.vue
<script>
import Stack from '@ej/components/stack';
import { updateValue } from '@ej/spo/api';
import dompurify from 'dompurify';

export default {
    functional: true,

    props: {
        cell: {
            type: Object,
            required: true,
        },
        disable: {
            type: Boolean,
            default: false,
        },
        rowId: {
            type: Number,
            required: true,
        },
    },

    render(h, { props, $style, listeners }) {
        let element;
        // some other class like validation before request
        let setClass = (className) => {
            if (!element) return;
            let classNames = ['error', 'saved', 'saving'];
            classNames.forEach((name) => {
                element.classList.remove(name);
            });

            if (!className) return;
            element.classList.add(className);
        };

       
        let save = (updatedValue, cell, rowId) => {
            // post to server
            updateValue(updatedValue)
                .then((result) => {
                    setClass('saved');
                    setTimeout(() => {
                        setClass('');
                    }, 3000);

                    listeners.saved?.(result);
                })
                .catch(e => {
                    setClass('error');
                });
        };
        let onFocusOut = (event) => {
            element = event.target.closest('td');
            let updatedValue = event.target.innerText.trim();

            setClass('saving');

            event.target.innerHTML = dompurify.sanitize(updatedValue);
            save(updatedValue, props.cell, props.rowId);
        };

        return h('td', {
            class: [$style.cell, 'spo-table-cell'],
            attrs: {
                'data-disabled': props.disable,
            },
        }, [
            h(Stack, {
                props: {
                    verticalAlign: 'center',
                    fill: true,
                },
            }, [
                h('div', {
                    attrs: {
                        contenteditable: !props.disable,
                    },
                    class: $style.content,
                    on: {
                        blur: onFocusOut,
                    },
                    domProps: {
                        innerHTML: props.cell.value || '',
                    },
                }),
            ]),
        ]);
    },
};
</script>

<style lang="less" module>
// some styles
</style>

The first is render and second is re-render after cell update

Performance of update. Function createFunctionalComponent has been called 802 times

What could be causing this discrepancy in re-render behavior between functional components and stateful components in Vue? How can I ensure that only the updated cells re-render in the table when using functional components, similar to the behavior observed with stateful template components?

Upvotes: 1

Views: 63

Answers (0)

Related Questions