使用Vue3实现在数组中高效重置特定值的方法?

huangapple go评论60阅读模式
英文:

Using Vue3 to implement an efficient way to reset specific value in array?

问题

如何使用Vue3来实现对数组中特定值进行高效重置?我尝试复制原始数据进行临时存储,然后使其不可变并重置值,或者使用其他方法来实现这个目标?

<script setup>
import { ref, computed, toRaw, watch } from 'vue';
const selected = ref(null);

const data = ref([{
  id: 1,
  label: 'A',
  value: 'A',
  name: 'Student A'
}, {
  id: 2,
  label: 'B',
  value: 'B',
  name: 'Student B'
}, {
  id: 3,
  label: 'C',
  value: 'C',
  name: 'Student C'
}]);

const initData = structuredClone(toRaw(data.value.reduce((acc, item) => {
  acc[item.id] = item.value;
  return acc;
}, {})));

watch(selected, (v) => {
  if (v === null) {
    data.value.forEach(item => item.value = initData[item.id]);
  } else {
    data.value.forEach(item => item.value = v);
  }
});
</script>

<template>
  <div>
    <select v-model="selected">
      <option :value="null">初始值</option>
      <option value="A">A</option>
      <option value="B">B</option>
      <option value="C">C</option>
    </select>

    <template v-for="(item, idx) in data" :key="idx">
      <div style="display:flex ; align-items: center;margin-bottom: 16px;">
        <div style="margin-right:16px;"> Name:{{ item.name }}</div>
        <select :value="item.value" @change="updateValue(item.id, $event.target.value)">
          <option value="A">A</option>
          <option value="B">B</option>
          <option value="C">C</option>
        </select>
      </div>
    </template>
  </div>
</template>
英文:

How to Using Vue3 to implement an efficient way to reset specific value in array? I am trying to copy origin data for temporary storage, then make it immutable and reset value, or other methods to implement this?

Vue SFC Playground

<script setup>
import { ref, computed, toRaw, watch } from 'vue';
const selected = ref(null)

const data = ref([{
  id: 1,
  label: 'A',
  value: 'A',
  name: 'Student A'
}, {
  id: 2,
  label: 'B',
  value: 'B',
  name: 'Student B'
}, {
  id: 3,
  label: 'C',
  value: 'C',
  name: 'Student C'
}])

const initData = structuredClone(toRaw(data.value.reduce((acc, item) => {
  acc[item.id] = item.value;
  return acc;
}, {})))

watch(selected, (v) => {
  if (v === null) {
    data.value.forEach(item => item.value = initData[item.id])
  } else {
    data.value.forEach(item => item.value = v)
  }
})
</script>

<template>
  <div>
    <select v-model="selected">
      <option :value="null">Init Value</option>
      <option value="A">A</option>
      <option value="B">B</option>
      <option value="C">C</option>
    </select>

    <template v-for="(item, idx) in data" :key="idx">
      <div style="display:flex ; align-items: center;margin-bottom: 16px;">
        <div style="margin-right:16px;"> Name:{{ item.name }}</div>
        <select :value="item.value" @change="updateValue(item.id, $event.target.value)">
          <option value="A">A</option>
          <option value="B">B</option>
          <option value="C">C</option>
        </select>
      </div>
    </template>
  </div>
</template>

答案1

得分: 0

你的措辞不太清晰,但我认为你在问你的工作代码是否可以改进?

如果是这样,我的第一个建议是用map替换reducemap用于转换数组的每个元素,而reduce通常用于将数组的所有值合并为单个值。你正在进行映射操作,但错误地使用了reduce函数来实现它。toRawstructuredClone也是完全不必要的。

第二个建议是用函数替换watch。对事件的响应,尤其是用户交互,适合使用函数。这不是watch的用例,watch通常用于对属性变化或异步操作结果的响应(一般规则是,只有在不能用函数或计算属性实现所需功能时,才使用watch)。

const initData = data.value.map(item => item.value)

const valueSelected = () => {
  if (selected.value === null) {
    data.value.forEach((item, i) => item.value = initData[i])
  } else {
    data.value.forEach(item => item.value = selected.value)
  }
}
<select v-model="selected" @change="valueSelected">

更新后的 Playground

英文:

Your wording is not clear, but I think you're asking if your working code could be made better?

If so, my first advice would be to replace the reduce with map. Map is for transforming each element of an array, while reduce is usually meant to merge all values of an array into a single value. What you are doing is mapping but incorrectly using the reduce function to do it. toRaw and structuredClone are also completely unnecessary.

Second would be to replace watch with a function. Reacting to an events, especially user interactions, is what functions are good for. It is not the use case for watch, which is usually meant for reacting to prop changes or reacting to the result of asynchronous operations (a general rule is, only if you can't do what you want with a function or computed property, then use watch).

const initData = data.value.map(item =&gt; item.value)

const valueSelected = () =&gt; {
  if (selected.value === null) {
    data.value.forEach((item, i) =&gt; item.value = initData[i])
  } else {
    data.value.forEach(item =&gt; item.value = selected.value)
  }
}
&lt;select v-model=&quot;selected&quot; @change=&quot;valueSelected&quot;&gt;

updated Playground

huangapple
  • 本文由 发表于 2023年6月1日 01:51:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/76376134.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定