[Enhancement]: Add "Large Mutable Structures" section to /guide/best-practices/performance.html?
Nobody has claimed this yet.
- Dominant language
- Vue
- Stars
- 3.2k
- Forks
- 5k
- Avg merge
- 14d 17h
- Merged PRs (30d)
- 1
Description
On the page about performance best practices, there's a section named Reduce Reactivity Overhead for Large Immutable Structures, which I found very enlightening. For example, if a Vue app fetches a long list of immutable objects used to populate a read-only table, then it makes sense to wrap that list in a shallowRef().
However, after reading the entire guide, I'm not sure what's the best way to handle large mutable state, specifically in terms of performance. For example, if I want to use a store to manage a lot of shared mutable state, which of the following 3 options is better strictly in terms of performance? (i.e. not in terms of code organization/code quality). Note that for simplicity, the state is not that big in the examples below, but image it contained 1000+ properties instead.
Option 1: Use a large and deeply-nested state object wrapped in a single ref()/reactive() instance:
// store.js
import { reactive } from "vue";
export const state = reactive({
user: {
name: "Alice",
email: "",
age: 0,
subscribed: false,
},
// many other properties, and some of them could be nested 10+ levels
});
// App.vue
<script setup>
import { computed } from "vue";
import { state } from "./store.js";
const text = computed(() => state.user.subscribed ? "Unsubscribe" : "Subscribe");
const toggle = () => state.user.subscribed = !state.user.subscribed;
</script>
<template>
<h1>Hello, {{ state.user.name }}!</h1>
<button @click="toggle()">{{ text }}</button>
</template>
Option 2: Split the large state object into many shallow ref()/reactive() instances:
// store.js
import { ref } from "vue";
export const userName = ref("Alice");
export const userEmail = ref("");
export const userAge = ref(0);
export const userSubscribed = ref(false);
// many other refs, but all of them contain primitive types
// App.vue
<script setup>
import { computed } from "vue";
import { userName, userSubscribed } from "./store.js";
const text = computed(() => userSubscribed.value ? "Unsubscribe" : "Subscribe");
const toggle = () => userSubscribed.value = !userSubscribed.value;
</script>
<template>
<h1>Hello, {{ userName }}!</h1>
<button @click="toggle()">{{ text }}</button>
</template>
Option 3: Use a large but flat state object wrapped in a single ref()/reactive() instance:
// store.js
import { reactive } from "vue";
export const state = reactive({
userName: "Alice",
userEmail: "",
userAge: 0,
userSubscribed: false,
// many other properties, but all of them contain primitive types (i.e. not nested)
});
// App.vue
<script setup>
import { computed } from "vue";
import { state } from "./store.js";
const text = computed(() => state.userSubscribed ? "Unsubscribe" : "Subscribe");
const toggle = () => state.userSubscribed = !state.userSubscribed;
</script>
<template>
<h1>Hello, {{ state.userName }}!</h1>
<button @click="toggle()">{{ text }}</button>
</template>
For option 1, my concern is that accessing or mutating very nested properties might cause more "reactivity overhead". For example, does the access of state.user.name and the mutation of store.user.subscribed in option 1 cause more overhead than the access of state.userName and the mutation of state.userSubscribed in option 3. Of course, in this case, the user name in option 1 is not that much more nested, but what if it was state.a.b.c.d.e.user.name instead, and we had hundreds or thousands of similar accesses/mutations across all the components in our app? Perhaps, there is zero overhead but it seems unclear from the documentation.
For option 2, my concern is that using many instances of ref()/reactive() could consume more memory and therefore could slow down performance for a large enough app. That said, I have a feeling that even when using a single ref()/reactive() instance as in options 1 and 3, Vue will recursively create more instances for child properties behind-the-scenes in order to provide "deep reactivity". Unfortunately, the simple implementation of ref() and reactive() in Reactivity in Depth doesn't handle deep reactivity, so it's unclear to me how the real Vue implementation would do it.
In short, code organization aside and strictly based on performance, is there one of these options that is better? I'm not sure if it's something that many Vue developers are struggling to understand (or even curious to know), so it might not warrant an addition to the performance page. You would know best, and thanks for your time!
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the performance best-practices page at guide/best-practices/performance.html and review its existing “Reduce Reactivity Overhead for Large Immutable Structures” section. Compare the three state-management options described in the issue, using the linked Reactivity in Depth and state-management pages as context. Done means deciding whether actionable guidance for large mutable state belongs in the guide and documenting a supported conclusion if it does.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript
- Domain
- documentation
- Issue type
- Documentation
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100