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

initial-values has issues with proxies, vee-validate should use toRaw on initial-values prop #4597

Closed
5 tasks done
lk77 opened this issue Dec 14, 2023 · 2 comments
Closed
5 tasks done

Comments

@lk77
Copy link

lk77 commented Dec 14, 2023

What happened?

Hello,

If a proxy object is passed to :initial-values, it cause issues with the setInPath function,

/**
 * Sets a nested property value in a path, creates the path properties if it doesn't exist
 */
function setInPath(object, path, value) {
    if (isNotNestedPath(path)) {
        object[cleanupNonNestedPath(path)] = value;
        return;
    }
    const keys = path.split(/\.|\[(\d+)\]/).filter(Boolean);
    let acc = object;
    for (let i = 0; i < keys.length; i++) {
        // Last key, set it
        if (i === keys.length - 1) {

            // Here if acc is a proxy object, a warning will be displayed in the console

            acc[keys[i]] = value;
            return;
        }
        // Key does not exist, create a container for it
        if (!(keys[i] in acc) || isNullOrUndefined(acc[keys[i]])) {
            // container can be either an object or an array depending on the next key if it exists
            acc[keys[i]] = isIndex(keys[i + 1]) ? [] : {};
        }
        acc = acc[keys[i]];
    }
}

this warning shows in the console, every time setInPath is used by FieldArray insert method for example

[Vue warn]: Detected a possible deep change on field `value` ref, for nested changes please either set the entire ref value or use `setValue` or `handleChange`,

Reproduction steps

use options api, i don't know if this issue is present in composition api

1 / Add a Form
2 / Add a FieldArray with a Field inside
3 / Add your initial values in the data of the component
4 / pass initialValues to the Form
5 / See the warning in the console when calling insert method of FieldArray
6 / Use markRaw on the initialValue to see that it solves the warning

Version

Vue.js 3.x and vee-validate 4.x

What browsers are you seeing the problem on?

  • Firefox
  • Chrome
  • Safari
  • Microsoft Edge

Relevant log output

runtime-core.esm-bundler.js:41 [Vue warn]: Detected a possible deep change on field `value` ref, for nested changes please either set the entire ref value or use `setValue` or `handleChange`. 
  at <Transition mode="out-in" name="fade" > 
  at *** > 
  at <BaseTransition appear=false persisted=false mode=undefined  ... > 
  at <Transition> 
  at ****
  at <App> 
  at <App>
warn @ runtime-core.esm-bundler.js:41
deep @ vee-validate.esm.js:1711
callWithErrorHandling @ runtime-core.esm-bundler.js:158
callWithAsyncErrorHandling @ runtime-core.esm-bundler.js:166
job @ runtime-core.esm-bundler.js:1831
flushPreFlushCbs @ runtime-core.esm-bundler.js:309
updateComponentPreRender @ runtime-core.esm-bundler.js:5916
componentUpdateFn @ runtime-core.esm-bundler.js:5834
run @ reactivity.esm-bundler.js:178
instance.update @ runtime-core.esm-bundler.js:5898
updateComponent @ runtime-core.esm-bundler.js:5725
processComponent @ runtime-core.esm-bundler.js:5660
patch @ runtime-core.esm-bundler.js:5124
patchBlockChildren @ runtime-core.esm-bundler.js:5511
patchElement @ runtime-core.esm-bundler.js:5403
processElement @ runtime-core.esm-bundler.js:5251
patch @ runtime-core.esm-bundler.js:5112
patchBlockChildren @ runtime-core.esm-bundler.js:5511
processFragment @ runtime-core.esm-bundler.js:5597
patch @ runtime-core.esm-bundler.js:5098
patchUnkeyedChildren @ runtime-core.esm-bundler.js:6005
patchChildren @ runtime-core.esm-bundler.js:5939
processFragment @ runtime-core.esm-bundler.js:5623
patch @ runtime-core.esm-bundler.js:5098
patchBlockChildren @ runtime-core.esm-bundler.js:5511
patchElement @ runtime-core.esm-bundler.js:5403
processElement @ runtime-core.esm-bundler.js:5251
patch @ runtime-core.esm-bundler.js:5112
componentUpdateFn @ runtime-core.esm-bundler.js:5857
run @ reactivity.esm-bundler.js:178
instance.update @ runtime-core.esm-bundler.js:5898
callWithErrorHandling @ runtime-core.esm-bundler.js:158
flushJobs @ runtime-core.esm-bundler.js:362
Promise.then (async)
queueFlush @ runtime-core.esm-bundler.js:275
queueJob @ runtime-core.esm-bundler.js:269
scheduler @ runtime-core.esm-bundler.js:1853
triggerEffect @ reactivity.esm-bundler.js:373
triggerEffects @ reactivity.esm-bundler.js:363
triggerRefValue @ reactivity.esm-bundler.js:966
eval @ reactivity.esm-bundler.js:1123
triggerEffect @ reactivity.esm-bundler.js:373
triggerEffects @ reactivity.esm-bundler.js:358
triggerRefValue @ reactivity.esm-bundler.js:966
eval @ reactivity.esm-bundler.js:1123
triggerEffect @ reactivity.esm-bundler.js:373
triggerEffects @ reactivity.esm-bundler.js:358
trigger @ reactivity.esm-bundler.js:335
set @ reactivity.esm-bundler.js:489
setInPath @ vee-validate.esm.js:371
insert @ vee-validate.esm.js:3299
checkInsert @ ***
eval @ ****
fn._withMods.fn._withMods @ runtime-dom.esm-bundler.js:1396
callWithErrorHandling @ runtime-core.esm-bundler.js:158
callWithAsyncErrorHandling @ runtime-core.esm-bundler.js:166
emit @ runtime-core.esm-bundler.js:669
eval @ ****
Promise.then (async)
nextTick @ runtime-core.esm-bundler.js:242
clickButton @ ****
onClick @ *****
callWithErrorHandling @ runtime-core.esm-bundler.js:158
callWithAsyncErrorHandling @ runtime-core.esm-bundler.js:166
invoker @ runtime-dom.esm-bundler.js:595

Demo link

github.com/lk77/test-vee-validate-bug

<template>
    <Form :initial-values="initialValues">
        <FieldArray name="locations" v-slot="{ fields, push, remove, insert }">
            <div v-for="(entry, idx) in fields" :key="entry.key">
                <Field :name="`locations[${idx}]`" v-slot="{ value, handleChange }">
                    <input :value="value.latitude"/>
                    <input :value="value.longitude"/>
                </Field>
                <button type="button" @click="remove(idx)">Remove</button>
                <button type="button" @click="insert(idx, {latitude: null, longitude: null})">Insert</button>
            </div>
            <button type="button" @click="push('')">Add</button>
        </FieldArray>
        <button>Submit</button>
    </Form>
</template>

<script>
    import {Form, FieldArray, Field} from "vee-validate";

    export default {
        name: 'Bug',
        components: {Form, FieldArray, Field},
        data() {
            return {
                initialValues: {
                    locations: [
                        {
                            latitude: null,
                            longitude: null
                        }
                    ]
                }
            }
        }
    }
</script>

<style scoped>

</style>

Screenshot from 2023-12-14 11-42-14
Screenshot from 2023-12-14 11-42-35

the only way to fix this issue is to use markRaw on the initial values like so :

initialValues: markRaw({
    locations: [
        {
            latitude: null,
            longitude: null
        }
    ]
})

Edit : for some reason, using markRaw on the initial values prevent the value to change when calling handleChange

Code of Conduct

@lk77 lk77 changed the title initial-values has issues with proxies initial-values has issues with proxies, vee-validate should use toRaw on initial-values prop Dec 14, 2023
@logaretm
Copy link
Owner

logaretm commented Dec 16, 2023

The warning itself isn't dangerous, its meant to catch people doing deep changes to the model. The reactivity is unrelated here because data get cloned.

I decided to remove the warning because it does not catch the specific case I want it to.

@lk77
Copy link
Author

lk77 commented Dec 17, 2023

Thanks !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants