SoFunction
Updated on 2025-04-05

vue problems and solutions encountered when using v-model to bind parent-child components in two-way

Scene

Use todayv-model I encountered a strange problem when performing two-way data binding of components. The web page itself is running normally and the browser keeps warning messages.

[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "value"

What caused this warning was a custom componentRxSelect

("RxSelect", {
 model: {
 prop: "value",
 event: "change",
 },
 props: {
 value: [Number, String],
 map: Map,
 },
 template: `
  <select
   v-model="value"
   @change="$emit('change', value)"
  >
   <option
   v-for="[k,v] in map"
   :value="k"
   :key="k"
   >{{v}}</option>
  </select>
  `,
});

The code we use seems to be fine?

&lt;main &gt;
 The currently selected gender is: {{(sex)}}
 &lt;div&gt;
 &lt;rx-select :map="map" v-model="sex" /&gt;
 &lt;/div&gt;
&lt;/main&gt;

JavaScript Code

new Vue({
 el: "#app",
 data: {
 map: new Map().set(1, "Confidential").set(2, "male").set(3, "female"),
 sex: "",
 },
});

After testing, the program itself is running normally, and there is no problem with passing the value of the parent-child component. The two-way data binding is indeed effective, but the browser keeps reporting errors.

Try to solve it

We found a way

  1. For variables that require two-way binding, inside the componentdataDeclare a variableinnerValueand initialize it tovalue
  2. existselectUse onv-modelBind this variableinnerValue
  3. monitorvalueChanges in parent componentvalueModify when changesinnerValueValue of
  4. monitorinnerValueChanges, use when changesthis.$emit('change', val)Tell the parent component that needs to be updatedvalueValue of
("RxSelect", {
 model: {
 prop: "value",
 event: "change",
 },
 props: {
 value: [Number, String],
 map: Map,
 },
 data() {
 return {
  innerValue: ,
 };
 },
 watch: {
 value(val) {
   = val;
 },
 innerValue(val) {
  this.$emit("change", val);
 },
 },
 template: `
 <select v-model="innerValue">
 <option
  v-for="[k,v] in map"
  :value="k"
  :key="k"
 >{{v}}</option>
 </select>
 `,
});

Using the code exactly the same, however the componentsRxSelectThere are a lot more codes. . .

solve

A more elegant way is to usecomputedComputational properties and theirget/set, the code increase is acceptable

("RxSelect", {
 model: {
 prop: "value",
 event: "change",
 },
 props: {
 value: [Number, String],
 map: Map,
 },
 computed: {
 innerValue: {
  get() {
  return ;
  },
  set(val) {
  this.$emit("change", val);
  },
 },
 },
 template: `
 <select v-model="innerValue">
 <option
  v-for="[k,v] in map"
  :value="k"
  :key="k"
 >{{v}}</option>
 </select>
 `,
});

The above is the detailed content of the problems and solutions encountered when using vue to bidirectionally bind the values ​​of parent-child components with v-model. For more information about vue to bidirectionally bind the values ​​of parent-child components with v-model, please pay attention to my other related articles!