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

Durations can't be used on properties in Vue because of internal mutability #1630

Open
hallipr opened this issue May 15, 2024 · 2 comments
Open

Comments

@hallipr
Copy link

hallipr commented May 15, 2024

Describe the bug
Because Duration.toFormat mutates the Duration, this causes recursive updates in Vue for components that run toFormat on Duration properties getters.

To Reproduce
with:

"dependencies": {
    "luxon": "^3.4.4",
    "vue": "^3.4.21"
  }

when I:

<template>
    <div>{{entry.duration.toFormat("hh:mm:ss")}}</div>
</template>

<script setup lang="ts">
import { reactive } from 'vue'
import { Duration } from 'luxon'

class Entry {
  public get duration() { return Duration.fromMillis(20000) }
}

const entry = reactive(new Entry())
</script

I get:

<div>00:00:20</div>

But I also get

[Vue warn]: Unhandled error during execution of app errorHandler
Uncaught (in promise) Maximum recursive updates exceeded in component <App>. This means you have a reactive effect that is mutating its own dependencies and thus recursively triggering itself. Possible sources include component template, render function, updated hook or watcher source function.

Actual vs Expected behavior
I would expect toFormat to not mutate the duration, but it does and this is detected by Vue.

Desktop (please complete the following information):

  • OS: Windows
  • Browser Chrome 124, Edge 124
  • Luxon version 3.4.4
  • Your timezone [e.g. "America/Los_Angeles"]

Additional context

This is another effect of the cause from #1104

I originally posted this as a StackOverflow question
https://stackoverflow.com/questions/78474017

@icambron
Copy link
Member

icambron commented May 15, 2024

Internal mutation is ok and is important for performance; these mutations in Luxon are just memoization. I think the issue is that we're not hiding it from Vue; i.e. Luxon's objects are immutable as far as the API is concerned, but Vue is seeing that notionally private members on the Duration object are changing, and it has no way to know they aren't part of an API. How does Vue detect mutations, and what's the supported way to hide things from it? This is supposed to be a tree-falls-in-the-woods sort of thing.

The gist here is that I'm willing to make changes that better support tools like Vue, but not at the expense of performance.

@Nicolas-Yazzoom
Copy link

You're likely looking for shallowReactive.

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

3 participants