This is the 20th day of my participation in the November Gwen Challenge. Check out the details: The last Gwen Challenge 2021

preface

What is the role of key in Vue? This problem should be familiar to everyone. Of course, I also contacted, but still stay in contact with this stage, when the real problem, almost stumble.

I have a problem

In recent days, there is a requirement to drag the table header, as shown in the figure, the fields in the right custom column are the fields displayed in the table, and the fields in the right custom column can be dragged, and the order after dragging is synchronized in the left table. In the process of practice, I found that after dragging and dropping on the right side, the display in the left table was wrong, for example, the title and the creation time and location were changed, but the first table rendered in the table was headed by the title, the second column was still the title, and the corresponding content below was correct, so what was the cause of this problem? Let’s look at my code implementation first.

Table drag code

Form code:

<div class="table-div">
<elable
  ref="table"
  v-loading="loading"
  :data="data"
  v-bind="tableProps"
  style="width: 100%;"
  :row-class-name="rowClassName"
  @header-dragend="handleDrag"
  @row-dblclick="dblclickRow"
  @sort-change="handleSortChange"
  @selection-change="onSelectionChange"
>
  <template v-if="columns.length > 0">
    <el-table-column
      v-for="(column, index) in columns"
      :key="index v-bind="column"
      :min-width="column.minWidth || 140"
      :resizable="true"
      :show-overflow-tooltip="true"
    />
  </template>
  <slot v-else />
</el-table>
</div>
Copy the code

Custom column drag component encapsulation code:

<div class="display-field-wrapper">
    <el-popover
      ref="display-field-popover"
      placement="bottom"
      width="216"
      popper-class="custom-field-popover"
      trigger="click"
    >
      <div class="display-field__popover-panel">
        <div class="screening-box">
          <el-select
            v-if="showGroup"
            v-model="typeValue"
            class="display-field__search"
            placeholder="All field types"
          >
            <el-option
              v-for="item in typeOptions"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            />
          </el-select>
        </div>
        <div class="display-field__title">
          <span class="select-title">{{ enableLabel }}</span>
          <span class="select-counts">{{ fieldCheckedList.length +'/'+ fieldLen }}</span>
        </div>
        <div class="display-field__checked-list">
          <draggable
            v-model="enableFieldsFilter"
            :draggable="draggableClass"
            @sort="onSort"
          >
            <div
              v-for="item in enableFieldsFilter"
              :key="item.prop"
              class="display-field__check-item"
              :class="{ 'display-field__draggable-item': item.can_cancel }"
            >
              <el-checkbox
                v-model="fieldCheckedList"
                :label="item.label"
                :disabled=! "" item.can_cancel"
                @change="handleCheck(item, -1)"
              />
            </div>
          </draggable>
        </div>
        <div class="display-field__title">
          <span class="select-title">{{ notEnableLabel }}</span>
          <span class="select-counts">{{ (fieldLen - fieldCheckedList.length) +'/'+ fieldLen }}</span>
        </div>
        <div class="display-field__unchecked-list">
          <div
            v-for="item in notEnableFieldsFilter"
            :key="item.prop"
            class="display-field__check-item"
          >
            <el-checkbox
              v-model="fieldCheckedList"
              :label="item.label"
              :disabled=! "" item.can_cancel"
              @change="handleCheck(item, 1)"
            />
          </div>
        </div>
      </div>
    </el-popver>
  </div>
Copy the code

In fact, when I was in the investigation, the first investigation in the component, thought that there was a problem with drag, but in fact, the content is right, just the table header has a problem, it just remembered a knowledge point before, to tell the truth, this point already know, but they did not encounter similar problems, so did not care. When I write a for loop, I usually do what I did in the code above, with the key as index, and I’ve never had a problem. Ha ha.

Key’s true role

Key is the identity of the virtual DOM object. When the data changes, VUE generates a new virtual DOM based on the new data, and then vUE compares the difference between the new virtual DOM and the old virtual DOM. What are the rules of comparison?

(1) The same key is found in the old virtual DOM as in the new virtual DOM: if the content in the virtual DOM remains unchanged, the previous real DOM is directly used; If the content in the virtual DOM changes, a new real DOM is generated, which then replaces the previous real DOM in the page.

(2) If the same key as the new virtual DOM is not found in the old virtual DOM, the new real DOM will be created and then rendered to the page.

Problem solving

That should answer my question above. I’m using index as the key, so when I drag and drop, when I compare, I find that the index hasn’t changed, so the content hasn’t changed either. Later, I added the key to index and a variable field, the column definition field, to ensure that the diff algorithm will change.

conclusion

In daily development, try to select the unique identifier of each data as key, such as ID, to avoid similar problems. If you do not add or delete data in reverse order, you can only use index as key for list rendering.

Happy Ending.