Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

when use custom v-model (with <script setup> style),it goes well in dev env,but may occur error:modelValue is undefined in production env #5584

Closed
CherishTheYouth opened this issue Mar 15, 2022 · 55 comments

Comments

@CherishTheYouth
Copy link

CherishTheYouth commented Mar 15, 2022

Version

3.2.31

Reproduction link

gitee.com

Steps to reproduce

(1)create a vue3 project with vite;
(2)write a parent component and a child component in <script setup>, use v-model for parent child component communication;
(3)it goes well in dev env,but occur error in prod env, the error as follows:

    index.8d23215e.js:1 Uncaught ReferenceError: modelValue is not defined
    at HTMLInputElement.u.onUpdate:modelValue.l.<computed>.l.<computed> [as _assign] (index.8d23215e.js:1)
    at HTMLInputElement.<anonymous> (vendor.52e08146.js:1)

What is expected?

I expect that my vue3 project which structured by vite.js will go well when use v-model write in <script setup> in prod dev.

What is actually happening?

Actually, it goes well in dev env but get the follow error in prod dev:

  index.8d23215e.js:1 Uncaught ReferenceError: modelValue is not defined
    at HTMLInputElement.u.onUpdate:modelValue.l.<computed>.l.<computed> [as _assign] (index.8d23215e.js:1)
    at HTMLInputElement.<anonymous> (vendor.52e08146.js:1)

NOTE:when I write it not in <script setup>, this error won't happen;
KeyWord:

  • vite
  • v-model (custom component)
  • in <script setup>
  • production env
@ygj6 ygj6 added 🐞 bug Something isn't working feat: compiler labels Mar 15, 2022
@LinusBorg LinusBorg added the p4-important Priority 4: this fixes bugs that violate documented behavior, or significantly improves perf. label Mar 15, 2022
@LinusBorg
Copy link
Member

Is there a more realistic scenario in which this happens?

In your example, you use v-model="modelValue", which is not allowed - you can't mutate props.

This is likely the root cause of the error: The compiler so far doesn't take this possibility into account as your can't v-model a prop directly..

@LinusBorg LinusBorg added 🔩 p2-edge-case and removed p4-important Priority 4: this fixes bugs that violate documented behavior, or significantly improves perf. labels Mar 15, 2022
@lidlanca
Copy link
Contributor

    <input :value="modelValue" @input="$emit('update:modelValue', $event.target.value)"/>

@LinusBorg
Copy link
Member

that doesn't create any problems.

@lidlanca
Copy link
Contributor

that is the working alternative.

a prop should technically not be used in v-model since its read-only, but the compiled output can still be more correct.
by referencing via __props in the vmodel logic.

also
<input v-model="someProp.x" /> will actually compile correctly with __props
which make sense, because only the top level is readonly.

someProp in template is referenced correctly __props.someProp
but in v-model it is referenced as a declared variable (someProp).

<script setup>
import {toRef} from "vue"

let props = defineProps(['someProp'])
// uncomment line will prevent error.
//const someProp = toRef(props,'someProp')
</script>

<template>

<input v-model="someProp" />
</template>

compiled output

return (_ctx, _cache) => {
  return _withDirectives((_openBlock(), _createElementBlock("input", {
    "onUpdate:modelValue": _cache[0] || (_cache[0] = $event => (_isRef(someProp) ? (someProp).value = $event : null))
  }, null, 512 /* NEED_PATCH */)), [
    [_vModelText, __props.someProp]
  ])
}
}

@CherishTheYouth
Copy link
Author

thank you all, I will modify my codes, best wishes for you two,god kiss you

@CherishTheYouth
Copy link
Author

@lidlanca @LinusBorg

@Shhu
Copy link

Shhu commented Apr 11, 2022

I run into this issue when deploying in production yesterday here is some example :
Default version
Its working without error, dev & prod

Setup version
Working in dev without warning or error, break in production :
Uncaught ReferenceError: modelValue is not defined at _createElementBlock.onUpdate:modelValue._cache.<computed>._cache.<computed> (about:srcdoc:50:74) at HTMLInputElement.<anonymous> (vue.runtime.esm-browser.js:10302:21)

@LinusBorg I understand v-model="modelValue" is not something you want, but it should throw a warning in dev at least, having an inconsistent behavior between dev and production is dangerous.

For this kind of component having <BaseCheckbox v-model="" /> instead of <BaseCheckbox v-model:value="" /> is nicer to me.

@LinusBorg
Copy link
Member

LinusBorg commented Apr 11, 2022

I didn't actually close this, the author did and j missed that.

@LinusBorg LinusBorg reopened this Apr 11, 2022
@edison1105
Copy link
Member

I feel it's a bug.

    } else {
      // v-model used on a potentially ref binding in <script setup> inline mode.
      // the assignment needs to check whether the binding is actually a ref.
      const altAssignment =
        bindingType === BindingTypes.SETUP_LET ? `${rawExp} = $event` : `null`
      assignmentExp = createCompoundExpression([
        `${eventArg} => (${context.helperString(IS_REF)}(${rawExp}) ? (`,
        createSimpleExpression(rawExp, false, exp.loc),
        `).value = $event : ${altAssignment})`
      ])
    }

@zkwolf
Copy link

zkwolf commented Apr 26, 2022

I also meet this problem, I think this error should be output in dev env.

@yyx990803 yyx990803 added this to Dev/Prod Inconsistency in Next Patch May 10, 2022
@jackkitley
Copy link

jackkitley commented Jun 6, 2022

app.js?id=a6222ed598160499e804f155d81a5a68:2 Uncaught ReferenceError: modelValue is not defined at HTMLSelectElement.onUpdate:modelValue.n.<computed>.n.<computed> [as _assign] (app.js?id=a6222ed598160499e804f155d81a5a68:2:81720) at HTMLSelectElement.<anonymous> (vendor.js?id=5ee158ef74247e1f887d62c380ab41c5:2:566971)

also getting this in prod

@jackkitley
Copy link

Is this a big issue? i see it was issued 28 days ago now @yyx990803 . Thanks!

@preeteshjain
Copy link

Hi @yyx990803 @LinusBorg

I have created a playground for this problem: Link

If click on the PROD button in menu, you will see this error message:

modelValue is not defined

Whereas in the DEV mode, everything works perfectly fine.

Expecting a fix to this problem, since its critical for making reusable components. Any suggestions for alternate approach is also appreciated 🙏


Attaching screenshots:

PROD Mode

sfc vuejs org_ (2)

DEV Mode

sfc vuejs org_ (3)

@ArkoxHub
Copy link

ArkoxHub commented Jul 4, 2022

This needs to be fixed as soon as possible. I wasted more than 2 hours because of this no-sense problem. Working dev but not in production without explanation is frustrating.
And there is no official solution.

@franklx
Copy link

franklx commented Jul 5, 2022

This bug is very annoying but there's a workaround:

if (import.meta.env.PROD) { var modelValue = toRef(props, 'modelValue') }

it's a ugly but it works, the only thing you need to adapt is the production check (import.meta.env.PROD is a Vite variable).

@preeteshjain
Copy link

This approach is even documented in docs, but it doesn't work in production:

image

@LinusBorg
Copy link
Member

@preeteshjain Your approach is not mutating an object or array prop, and you approach is still mutating a prop, so that's not what the docs recommend.

@NielsJorck
Copy link

I had a similar issue recently, the workaround I went with was creating a computed with a get and set. Passing the get to model and having the set emit the update.

const value = computed({
  get() {
    return props.modelValue;
  },
  set(value) {
    emit("update:modelValue", value);
  },
});
<input v-model="value"  />

@ArkoxHub
Copy link

ArkoxHub commented Jul 5, 2022

To be honest, I still do not understand this problem.
I have form components which are working as expected using <script setup> but the only one is not working in production is the BaseSelect component I created.

This is my code, let's see if you could see what's happening here, at least to understand the issue.

Partent component

<section class="categories"> <BaseSelect label="Selecciona la categoría" :options="getCategoryNames" v-model="categorySelected" /> </section>

export default { components: { BaseSelect }, data() { return { categorySelected: 'todos',
...

Child component

<script setup>
import UniqueID from '../../features/UniqueID';
const uuid = UniqueID().getID();

const props = defineProps({
    label: String,
    placeholder: String,
    options: [Array, Object],
    modelValue: [String, Number]
})

const emit = defineEmits(['update:modelValue'])
function updateValue(value) {
    emit('update:modelValue', value)
}

function getUID() {
    console.log(UniqueID);
}
</script>

<template>
    <div class="form-control">
        <label :for="uuid" v-if="label">{{ label }}</label>
        <select :id="uuid" :value="modelValue" class="input-field" v-bind="$attrs"
            @change="updateValue($event.target.value)">
            <option v-for="option in options" :value="option" :key="option" :selected="option === modelValue">
                <span>{{ option }}</span>
            </option>
        </select>
    </div>
</template>

As I said before, I have other form components created the exactly same way and they are all working fine. If you need an example of them, please let me know.

If you will, you can have a look in the console where the error happens in production:
https://www.amigoinvisible.net/regalos-amigo-invisible

Thanks.

@preeteshjain
Copy link

preeteshjain commented Jul 5, 2022

To everyone facing this issue, the only way to fix this problem is to make sure (double check carefully) that you are not modifying your props from child component.

We are now modifying the data from the parent only and passing it down as a prop to the child component and it is working in production environment.

Here's how I have fixed the problem in the example I shared above:

Note that each scenario is different and the solution above is just an example. Hope the solution gives some insipiration for you guys to fix your problem. You guys will have to figure out your own approach making sure you don't change Parent's props from Child component.

That being said, I think the only problem with Vue 3 currently is that it isn't notifying about this problem in DEV environment.

@ArkoxHub
Copy link

ArkoxHub commented Jul 5, 2022

Isn't it the main purpose of 2 way data binding? The availability to change the value of a property either in parent or child component?

@Shhu
Copy link

Shhu commented Jul 5, 2022

@preeteshjain There is two issues :

  • Different behavior between dev and prod (and thats a huge problem)
  • Different behavior between legacy component and setup component

@evanerwee01
Copy link

I have exactly this problem. I'm new to vue.js and spent nearly 20 hours to found the issue mentioned. I still cant fix the problem. SPent 2 hours reading here, over and over again, but to luck. Anyone that can explain a bit more I will greatly apprechiate. I'm a programmer and coding for many years. Just not a JAVA /TS coder.

My code

`<script setup>
import {toRef} from "vue"

let props = defineProps(['accessKey','secretKey'])

const accessKey = toRef(props,'accessKey')
const secretKey = toRef(props,'secretKey')

</script>
Access Key:

Secret Key:

`

@evanerwee01
Copy link

image

My error message

@dulshan300
Copy link

@evanerwee01 as per the Vue docs, toRef required reactive source since defineProps returns a read-only Object
Vuejs#toRef

but you can use

const accessKey = ref(props.accessKey)
const secretKey = ref(props.secretKey)

@mileusna
Copy link

mileusna commented Aug 23, 2022

My fist Vue project, everything is working fine and then after "npm run build" I ran into this bug, what a bad luck! And here I am after lots of googling. Yes, moving everything from <script setup> to <script> solves the problem, thank you for that.

Fairly simple code for this view. I have just removed login procedure from the code. <div>{{ username }}</div> is there to demonstrate the bug.

<script setup>
import axios from 'axios'
import VueCookies from 'vue-cookies';
</script>


<script>
export default {
    data() {
        return {
            username: '',
            password: '',
        }
    },
    methods: {
        submitForm() {
            // axios logging, set cookie and redirect
        },
   },
}

</script>

<template>
    <div>
        <div>{{ username }}</div>
        <form v-on:submit.prevent="submitForm">
            Username: <input type="text" name="username" v-model="username" class="border p-1" /><br />
            Password: <input type="password" name="password" v-model="password" class="border p-1" />
            <input type="submit" value="Login" class="border p-1 bg-slate-500" />
        </form>
    </div>
</template>

@xcash
Copy link

xcash commented Aug 26, 2022

Ok guys (and @mileusna in particular) we've just faced this issue when releasing in production. We had a component which used a "mixed mode".
We had a <script setup> with all the imports and a legacy <script> section with the old-style component code using data().
In development it worked flawlessy but in production it was unable to find the data variables after startup.

We found that the mixed file style was the problem.

You need to use script setup OR script .
When using both it seems that the production context doesn't contain the data variables defined in the <script> tag.
Something related to the preproces/compiling optimizations for production maybe.

So this IS INDEED a bug to be solved. As the mixed behaviour of dev/prod is a huge problem.
But we need also to clearly define the best practice here. Use only one style? (preferred imho) or how to merge template variables when using both styles?

@mileusna
Copy link

mileusna commented Aug 26, 2022

Ok guys (and @mileusna in particular) we've just faced this issue when releasing in production. We had a component which used a "mixed mode".

Give me something else that I can break. 😂

Although I'm 20+ years in software development, this is my first contact with Vue or any other SPA JS framework, so yes I still don't have full understanding of <script setup> and <script> and how stuff works in Vue, and I try to build things fast while learning at the same time.

The main issue is that it works in dev but not in production. If it was broken in dev I would probably figured out the right way to do it.

@M1CK431
Copy link

M1CK431 commented Sep 12, 2022

Hi,

It happens to me with a getter/setter computed.

In the following example, SomeComponent accept a modelValue prop of Object type.
This child component is not mutating the prop. Instead, it emits an update:modelValue event with a modified thing object (for example, the id will remains the same but the name will be changed) using a code like that: $emit('update:modelValue', { ...modelValue, name: 'new thing name' })

Works in dev build, but not in prod build:

<template>
  <button @click="thingId = 0">Select first thing</button>
  <button @click="thingId = 1">Select second thing</button>

  <SomeComponent v-model="thing" />
</template>

<script>
export default {
  data: () => ({
    things: [{ id: 0, name: "something" }, { id: 1, name: "something else" }],
    thingId: 0
  }),
  computed: {
    thing: {
      get: ({ things, thingId }) => things.find(({ id }) => id === thingId),
      set(thing) {
        Object.assign(this.thing, thing);
      }
    }
  }
};
</script>

Result: console error similar to others about undefined modelValue bla bla bla...

Now let's replace the computed setter with a method, while keeping exactly the same code, but this time it will works in both Dev en Prod build:

<template>
  <button @click="thingId = 0">Select first thing</button>
  <button @click="thingId = 1">Select second thing</button>

  <SomeComponent :modelValue="thing" @update:modelValue="handleThingUpdate" />
</template>

<script>
export default {
  data: () => ({
    things: [{ id: 0, name: "something" }, { id: 1, name: "something else" }],
    thingId: 0
  }),
  computed: {
    thing: ({ things, thingId }) => things.find(({ id }) => id === thingId)
  },
  methods: {
    handleThingUpdate(thing) {
      Object.assign(this.thing, thing);
    }
  }
};
</script>

@LinusBorg since in this example there is no prop at all in the component, I guess your arg about "mutating a prop" isn't applicable here, right? In addition, that code isn't mutating the computed value itself because an Object.assign use the object reference to update the object properties, not the object reference itself. The fact that it works in a method proves that, right?

@fzn0x
Copy link

fzn0x commented Sep 13, 2022

Ok guys (and @mileusna in particular) we've just faced this issue when releasing in production. We had a component which used a "mixed mode". We had a <script setup> with all the imports and a legacy <script> section with the old-style component code using data(). In development it worked flawlessy but in production it was unable to find the data variables after startup.

We found that the mixed file style was the problem.

You need to use script setup OR script . When using both it seems that the production context doesn't contain the data variables defined in the <script> tag. Something related to the preproces/compiling optimizations for production maybe.

So this IS INDEED a bug to be solved. As the mixed behaviour of dev/prod is a huge problem. But we need also to clearly define the best practice here. Use only one style? (preferred imho) or how to merge template variables when using both styles?

Deleting script setup solved my issue, it's now works on both DEV and PROD environment, thanks!

@M1CK431
Copy link

M1CK431 commented Sep 14, 2022

Just to clarify, there is "Options API" and "Composition API", none of them are "legacy" or "old style".
src: https://vuejs.org/guide/extras/composition-api-faq.html#will-options-api-be-deprecated

In addition, there is still one thing which can't be done in composition API at all: disabling inheritAttrs.
src: https://vuejs.org/guide/extras/composition-api-faq.html#does-composition-api-cover-all-use-cases

Keeping that in mind, we already an answer to the question:

But we need also to clearly define the best practice here. Use only one style? (preferred imho) or how to merge template variables when using both styles?

We also have official advises here:

I guess this is enough, right? 😉

So now, the real question is: can we hope an official statement, or even better a fix, to the consistency issue between dev/prod build which is encountered by many dev in various scenario? @LinusBorg ? 🥺

@LinusBorg
Copy link
Member

LinusBorg commented Sep 14, 2022

@M1CK431 Hi. Yes, we have an inconsistencies here. The one originally reported in this issue is an edge case as really, it's an invalid use of v-model on a prop. As such, it does not have high priority.

The one you now reported sounds similar, yet would be a separate issue as the original one is related to a compiler issue with script setup, which your example does not use. However, I tried to reproduce it and failed:

See this Playground

TBH, I'm not even sure what error to look for as you never mentioned how it does not work in prod.

Could you have a look and maybe adjust my attempt to reproduce the issue you are seeing? if it only happens in a real project build, please provide a small repro in a separate issue.

@M1CK431
Copy link

M1CK431 commented Sep 14, 2022

Thanks for this quick reply and confirmation @LinusBorg 🙏

The one originally reported in this issue is an edge case as really, it's an invalid use of v-model on a prop. As such, it does not have high priority.

=> I agree, my linter is reporting me this kind of mistake (v-model on a prop). In addition, the documentation explicitly stand it's forbidden: https://vuejs.org/guide/components/props.html#one-way-data-flow

The one you now reported sounds similar, yet would be a separate issue as the original one is related to a compiler issue with script setup, which your example does not use.

=> You are perfectly right, I'm sorry and will open a dedicated issue.

TBH, I'm not even sure what error to look for as you never mentioned how it does not work in prod.

=> mmmm ok, I was thinking it was clear enough when I was explaining:

Result: console error similar to others about undefined modelValue bla bla bla...

But now I figure it was not so clear in fact... 🤭 To be more precise, the object property isn't updated in the parent component when the child component emit the update:modelValue event, and instead an error appears in the browser console similar to the one reported in this issue (I start to report it here by googling my error message) about this.thing is undefined or something like this.

The playground you provide looks good and, as I was explaining, is similar to the behavior I have in build dev (aka everything works as expected). The issue happens only with prod build.

Could you have a look and maybe adjust my attempt to reproduce the issue you are seeing? if it only happens in a real project build, please provide a small repro in a separate issue

=> Unfortunately, the project I'm working on is closed source so I can't directly provide the code. However, I will try to provide a repo, with a source code producing a working dev build but a not working prod build (and both will be in the repo too).

Again, thanks a lot for the time you take to reply and try to reproduce the issue 😘

@M1CK431
Copy link

M1CK431 commented Sep 15, 2022

@LinusBorg I just open a dedicated issue with a reproduction repo here: #6677
Please notice that, at the end, it's effectively related to <script> and <script setup> mixed usage.

@xcash
Copy link

xcash commented Sep 16, 2022

We also have official advises here:

I guess this is enough, right? wink

Well, the docs states:

For learning purposes, go with the style that looks easier to understand to you. 
Again, most of the core concepts are shared between the two styles. 
You can always pick up the other style later.
For production use:

Go with Options API if you are not using build tools, or plan to use Vue primarily in low-complexity scenarios, e.g. progressive enhancement.

Go with Composition API + Single-File Components if you plan to build full applications with Vue.

And then

Can I use both APIs together?[#](https://vuejs.org/guide/extras/composition-api-faq.html#can-i-use-both-apis-together)
Yes. You can use Composition API via the [setup()](https://vuejs.org/api/composition-api-setup.html) option in an Options API component.

However, we only recommend doing so if you have an existing Options API codebase that needs to integrate with new features / external libraries written with Composition API.

So this states that yes, you can use it but it's advised to choose one or the other unless you know what you're doing.

For a newbie this is quite confusing. But I agree that, reading this with the proper mindset fully covers the point.

So now, the real question is: can we hope an official statement, or even better a fix, to the consistency issue between dev/prod build which is encountered by many dev in various scenario? @LinusBorg ? pleading_face

Yes. This is the real problem as this is a bug in compilation/transpiling related to that type of setup.

@M1CK431
Copy link

M1CK431 commented Sep 16, 2022

@xcash take a look at #6677, that type of setup is unsupported in fact. Dev have to choose one single API per component.
I have take a long time to explain why it could be a good idea to start supporting it, but TBH I think its a lost cause, unfortunately.

Anyway we now have a clear statement and it's already a good point 👍

@lucassimines
Copy link

I had a similar issue recently, the workaround I went with was creating a computed with a get and set. Passing the get to model and having the set emit the update.

const value = computed({
  get() {
    return props.modelValue;
  },
  set(value) {
    emit("update:modelValue", value);
  },
});
<input v-model="value"  />

This is the best solution, thanks @NielsJorck.

@Sabirhussain1122
Copy link

Sabirhussain1122 commented Sep 30, 2022

this issue
selected is define in data() {selected:[],}
Tests.307cfab5.js:1 Uncaught ReferenceError: selected is not defined
at t.id.t.status.a.onUpdate:modelValue.s..s. (Tests.307cfab5.js:1:8045)
at HTMLInputElement. (app.6c599ef3.js:31:66663)

@GaoBlues2
Copy link

Ok guys (and @mileusna in particular) we've just faced this issue when releasing in production. We had a component which used a "mixed mode". We had a <script setup> with all the imports and a legacy <script> section with the old-style component code using data(). In development it worked flawlessy but in production it was unable to find the data variables after startup.

We found that the mixed file style was the problem.

You need to use script setup OR script . When using both it seems that the production context doesn't contain the data variables defined in the <script> tag. Something related to the preproces/compiling optimizations for production maybe.

So this IS INDEED a bug to be solved. As the mixed behaviour of dev/prod is a huge problem. But we need also to clearly define the best practice here. Use only one style? (preferred imho) or how to merge template variables when using both styles?

Thanks, it really helps me.

@quangddinh
Copy link

I have solved this problem like this.

<template>
  <div>
    <input
      v-model="val"
      @change="onChange" />
  </div>
</template>
<script setup lang="ts">
  import { ref } from 'vue'

  const props = defineProps({value: {},})

  const val = ref(props.value)

  const emit = defineEmits<{(event: 'onChange', value: any): void}>()

  const onChange = () => {
    emit('onChange', val.value)
  }
</script>

@nicszerman
Copy link

nicszerman commented Oct 18, 2022

This problem is happening to me too. I jumped into the source code and found that modifying the produced code like this fixes the problem:

PRODUCED CODE
"onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => isRef(draftMessage) ? draftMessage.value = $event : null)

FIXED PRODUCED CODE
"onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => isRef(_ctx.draftMessage) ? _ctx.draftMessage.value = $event : null)

So there's a bug when adding _ctx. prefix in produced code.

draftMessage is a state variable. JSX where this is happening:

<textarea
                class="peer w-full ml-2 px-2 bg-slate-50
                        rounded-md rounded-tr-none rounded-br-none
                        overflow-hidden resize-none
                        outline outline-0 focus:outline-1
                        outline-slate-400/20 focus:drop-shadow-sm"                        
                ref="draftMessageBar"
                @keydown.enter="sendMessage"
                v-model="draftMessage" placeholder="type message"
                @mousedown="draftMessageBarSendIconColor = '#a8a29e' /* stone-400 */"
                @blur="draftMessageBarSendIconColor = '#d6d3d1' /* stone-300 */">
              </textarea>

@IT-Tagore
Copy link

图像

我的错误消息

me too

@davidoskay
Copy link

Found another solution:

Change:
v-model="variable"
to
:modelValue="variable" @update:modelValue="variable = $event"

It should be the same but it's not... why?

@yyx990803
Copy link
Member

Summary:

  • Using v-model on a prop is incorrect usage: a prop's local binding is not writable, so the reverse update never worked as intended. For correct component v-model usage, consult the relevant section in docs. Note the docs never showed any usage of using v-model on a prop.

  • The fundamental issue here is the behavior inconsistency between prod and dev. In dev, it did not throw an error and failed silently - as seen in the original repro, the parent value does not update when typing. The only update is triggered on the blur event which emitted the update:modelValue event. In prod, the template is compiled inline and produces different code. Because we never assumed this usage, the production codegen did not take this into account and causes a confusing runtime error.

001184e added a new compile-time error that prevents using v-model on a prop binding. This should not constitute a breaking change since previously the usage breaks in production anyway.

@IT-Tagore
Copy link

vue3:
v-model="props.modelValue",
const emits = defineEmits(['update:modelValue'])
use watch or computed
watch(
() => props.modelValue,
(val) => {
emits('update:modelValue', val)
},
{ deep: true }
)

outUse:
v-model:model-value="youValue",

可以解决在dev环境正常,但是在testprod环境抛出错误的问题。

@zengshenggit
Copy link

Oh, so that how it is.

@ErosBurastero
Copy link

It is possible to change emit() for const emit = defineEmits() ?? because with emit() doesn't work properly, thanks

@LaKing
Copy link

LaKing commented Jan 15, 2023

I came across this issue, with my custom components, that emit update objects for the v-model.
In production, I got the error. TypeError: invalid assignment to const 'data'

After making sure my props are only used in read only by cloning them to local versions the issue was still present.

The solution in my case was to use properties of reactive objects in v-model, rather then using the reactive objects themselves.

In script setup of the custom element's parent

const data = reactive({});

In script setup of the custom element

// clone is an implementation for structured cloning
const data = reactive(clone(props.modelValue));

const updateHandler = () => {
    emit("update:modelValue", clone(data));
    emit("update", clone(data));
    emit("update:valid", isValid());
};

The error referred to the parent component

 <custom-component v-model="data" />

The working way was to use the reactive object's properties in the model. (that)

 <custom-component v-model="data.that" />

After modifying all my components to that pattern, production is now error free.
Vue 3.2.45

Note: I use both script and script setup in my components.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Next Patch
Dev/Prod Inconsistency
Development

No branches or pull requests