I've done some basic benchmarking wondering if I should provide/inject frequently used variables or if I should access them from a Pinia store in a big number of components.
The results suggest that there is no substantial performance difference.
My first test case is very basic:
Provide/inject a single bool
vs get it from a Pinia store in a component and render the component many times.
50k component renders took the time varying between 20-24s, same while using provide/inject and while using Pinia. There is no consistent difference to say any of the two are faster/slower.
In the second test I've used a larger object, an array of roughly 1MiB data (measured as printed in white-space-less JSON). The difference again is non-significant. I've rendered 50k component and it took about the same time, between 19-26s both with inject and with store access.
The components in each case rendered the boolean casted value of the subject variable, so their render time was not inflated with the large data vs the small boolean.
After all this I've concluded that there is really no meaningful difference between provide/inject vs. a Pinia store. The only apparent difference is that with larger data the performance is less stable, with the small data it is more predictable. No matter how many times I've repeated the tests for the boolean, the time was always between 20-24s, with the larger data I've got some outliers such as 19s or 26s. Again nothing consistent, it is likely just the fluctuations of my actual CPU usage, and it is not related to the usage of provide/inject vs. Pinia store.
I've did the tests with Chrome v110 (x86_64) on macOS using vue@3.2.47 & pinia@2.0.32.
Test code I've used:
<template>
<div>Inject {{ number }}: {{ injected ? 'yes' : 'no' }}</div>
</template>
<script setup lang="ts">
export interface Props {
number?: number,
}
const props = withDefaults( defineProps<Props>(), {
number: 0,
})
import { inject } from 'vue'
const injected = inject('inject-test')
</script>
<template>
<div>Store get {{ number }}: {{ testStore.test ? 'yes' : 'no' }}</div>
</template>
<script setup lang="ts">
export interface Props {
number?: number,
}
const props = withDefaults( defineProps<Props>(), {
number: 0,
})
import { useTestStore } from 'stores/test'
const testStore = useTestStore()
</script>
<template>
<div v-if="testStore">
<h1>Store get</h1>
<pre>Start: {{ start() }}</pre>
<div class="test">
<StoreGet v-for="n in 50000"
:key="n"
:number="n"
/>
</div>
<pre>End: {{ end() }}</pre>
<pre>Duration: {{ endTime - startTime }} seconds</pre>
</div>
<div v-else>
<h1>Inject</h1>
<pre>Start: {{ start() }}</pre>
<div class="test">
<Inject v-for="n in 50000"
:key="n"
:number="n"
/>
</div>
<pre>End: {{ end() }}</pre>
<pre>Duration: {{ endTime - startTime }} seconds</pre>
</div>
</template>
<script setup lang="ts">
import { provide } from 'vue'
import Inject from './test/Inject.vue'
import StoreGet from './test/StoreGet.vue'
// Roughly 1M of json data
import { large } from '@sbnc/datasets/largeTest'
// Comment one or the other:
const testData = true
//const testData = large
// Choose which one to test:
const testStore = true // set false to test inject
provide( 'inject-test', testData)
import { useTestStore } from 'stores/test'
const testStore = useTestStore()
testStore.test = testData
let startTime
let endTime
function start() {
startTime = performance.now()
return startTime
}
function end() {
endTime = performance.now()
return endTime
}
</script>