Use shallowRef instead of ref in .vue files where possible (#34813)

This PR improves some `.vue` components by using `shallowRef instead of
ref`, which `should improve performance`. It's probably not significant,
but it's an improvement because Vue no longer deep watches the ref
(shallowRef). Also i used `useTemplateRef` instead of `ref`.

---------

Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
Kilisei 2025-06-22 15:37:03 +02:00 committed by GitHub
parent a46b16f10f
commit 181db69e0c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 51 additions and 51 deletions

View File

@ -1,7 +1,7 @@
<script lang="ts" setup> <script lang="ts" setup>
// TODO: Switch to upstream after https://github.com/razorness/vue3-calendar-heatmap/pull/34 is merged // TODO: Switch to upstream after https://github.com/razorness/vue3-calendar-heatmap/pull/34 is merged
import {CalendarHeatmap} from '@silverwind/vue3-calendar-heatmap'; import {CalendarHeatmap} from '@silverwind/vue3-calendar-heatmap';
import {onMounted, ref} from 'vue'; import {onMounted, shallowRef} from 'vue';
import type {Value as HeatmapValue, Locale as HeatmapLocale} from '@silverwind/vue3-calendar-heatmap'; import type {Value as HeatmapValue, Locale as HeatmapLocale} from '@silverwind/vue3-calendar-heatmap';
defineProps<{ defineProps<{
@ -24,7 +24,7 @@ const colorRange = [
'var(--color-primary-dark-4)', 'var(--color-primary-dark-4)',
]; ];
const endDate = ref(new Date()); const endDate = shallowRef(new Date());
onMounted(() => { onMounted(() => {
// work around issue with first legend color being rendered twice and legend cut off // work around issue with first legend color being rendered twice and legend cut off

View File

@ -2,16 +2,16 @@
import {SvgIcon} from '../svg.ts'; import {SvgIcon} from '../svg.ts';
import {GET} from '../modules/fetch.ts'; import {GET} from '../modules/fetch.ts';
import {getIssueColor, getIssueIcon} from '../features/issue.ts'; import {getIssueColor, getIssueIcon} from '../features/issue.ts';
import {computed, onMounted, ref} from 'vue'; import {computed, onMounted, shallowRef, useTemplateRef} from 'vue';
import type {IssuePathInfo} from '../types.ts'; import type {IssuePathInfo} from '../types.ts';
const {appSubUrl, i18n} = window.config; const {appSubUrl, i18n} = window.config;
const loading = ref(false); const loading = shallowRef(false);
const issue = ref(null); const issue = shallowRef(null);
const renderedLabels = ref(''); const renderedLabels = shallowRef('');
const i18nErrorOccurred = i18n.error_occurred; const i18nErrorOccurred = i18n.error_occurred;
const i18nErrorMessage = ref(null); const i18nErrorMessage = shallowRef(null);
const createdAt = computed(() => new Date(issue.value.created_at).toLocaleDateString(undefined, {year: 'numeric', month: 'short', day: 'numeric'})); const createdAt = computed(() => new Date(issue.value.created_at).toLocaleDateString(undefined, {year: 'numeric', month: 'short', day: 'numeric'}));
const body = computed(() => { const body = computed(() => {
@ -22,7 +22,7 @@ const body = computed(() => {
return body; return body;
}); });
const root = ref<HTMLElement | null>(null); const root = useTemplateRef('root');
onMounted(() => { onMounted(() => {
root.value.addEventListener('ce-load-context-popup', (e: CustomEventInit<IssuePathInfo>) => { root.value.addEventListener('ce-load-context-popup', (e: CustomEventInit<IssuePathInfo>) => {

View File

@ -1,6 +1,6 @@
<script lang="ts" setup> <script lang="ts" setup>
import {SvgIcon, type SvgName} from '../svg.ts'; import {SvgIcon, type SvgName} from '../svg.ts';
import {ref} from 'vue'; import {shallowRef} from 'vue';
import {type DiffStatus, type DiffTreeEntry, diffTreeStore} from '../modules/diff-file.ts'; import {type DiffStatus, type DiffTreeEntry, diffTreeStore} from '../modules/diff-file.ts';
const props = defineProps<{ const props = defineProps<{
@ -8,7 +8,7 @@ const props = defineProps<{
}>(); }>();
const store = diffTreeStore(); const store = diffTreeStore();
const collapsed = ref(props.item.IsViewed); const collapsed = shallowRef(props.item.IsViewed);
function getIconForDiffStatus(pType: DiffStatus) { function getIconForDiffStatus(pType: DiffStatus) {
const diffTypes: Record<DiffStatus, { name: SvgName, classes: Array<string> }> = { const diffTypes: Record<DiffStatus, { name: SvgName, classes: Array<string> }> = {

View File

@ -1,19 +1,19 @@
<script lang="ts" setup> <script lang="ts" setup>
import {computed, onMounted, onUnmounted, ref, watch} from 'vue'; import {computed, onMounted, onUnmounted, shallowRef, watch} from 'vue';
import {SvgIcon} from '../svg.ts'; import {SvgIcon} from '../svg.ts';
import {toggleElem} from '../utils/dom.ts'; import {toggleElem} from '../utils/dom.ts';
const {csrfToken, pageData} = window.config; const {csrfToken, pageData} = window.config;
const mergeForm = ref(pageData.pullRequestMergeForm); const mergeForm = pageData.pullRequestMergeForm;
const mergeTitleFieldValue = ref(''); const mergeTitleFieldValue = shallowRef('');
const mergeMessageFieldValue = ref(''); const mergeMessageFieldValue = shallowRef('');
const deleteBranchAfterMerge = ref(false); const deleteBranchAfterMerge = shallowRef(false);
const autoMergeWhenSucceed = ref(false); const autoMergeWhenSucceed = shallowRef(false);
const mergeStyle = ref(''); const mergeStyle = shallowRef('');
const mergeStyleDetail = ref({ const mergeStyleDetail = shallowRef({
hideMergeMessageTexts: false, hideMergeMessageTexts: false,
textDoMerge: '', textDoMerge: '',
mergeTitleFieldText: '', mergeTitleFieldText: '',
@ -21,33 +21,33 @@ const mergeStyleDetail = ref({
hideAutoMerge: false, hideAutoMerge: false,
}); });
const mergeStyleAllowedCount = ref(0); const mergeStyleAllowedCount = shallowRef(0);
const showMergeStyleMenu = ref(false); const showMergeStyleMenu = shallowRef(false);
const showActionForm = ref(false); const showActionForm = shallowRef(false);
const mergeButtonStyleClass = computed(() => { const mergeButtonStyleClass = computed(() => {
if (mergeForm.value.allOverridableChecksOk) return 'primary'; if (mergeForm.allOverridableChecksOk) return 'primary';
return autoMergeWhenSucceed.value ? 'primary' : 'red'; return autoMergeWhenSucceed.value ? 'primary' : 'red';
}); });
const forceMerge = computed(() => { const forceMerge = computed(() => {
return mergeForm.value.canMergeNow && !mergeForm.value.allOverridableChecksOk; return mergeForm.canMergeNow && !mergeForm.allOverridableChecksOk;
}); });
watch(mergeStyle, (val) => { watch(mergeStyle, (val) => {
mergeStyleDetail.value = mergeForm.value.mergeStyles.find((e: any) => e.name === val); mergeStyleDetail.value = mergeForm.mergeStyles.find((e: any) => e.name === val);
for (const elem of document.querySelectorAll('[data-pull-merge-style]')) { for (const elem of document.querySelectorAll('[data-pull-merge-style]')) {
toggleElem(elem, elem.getAttribute('data-pull-merge-style') === val); toggleElem(elem, elem.getAttribute('data-pull-merge-style') === val);
} }
}); });
onMounted(() => { onMounted(() => {
mergeStyleAllowedCount.value = mergeForm.value.mergeStyles.reduce((v: any, msd: any) => v + (msd.allowed ? 1 : 0), 0); mergeStyleAllowedCount.value = mergeForm.mergeStyles.reduce((v: any, msd: any) => v + (msd.allowed ? 1 : 0), 0);
let mergeStyle = mergeForm.value.mergeStyles.find((e: any) => e.allowed && e.name === mergeForm.value.defaultMergeStyle)?.name; let mergeStyle = mergeForm.mergeStyles.find((e: any) => e.allowed && e.name === mergeForm.defaultMergeStyle)?.name;
if (!mergeStyle) mergeStyle = mergeForm.value.mergeStyles.find((e: any) => e.allowed)?.name; if (!mergeStyle) mergeStyle = mergeForm.mergeStyles.find((e: any) => e.allowed)?.name;
switchMergeStyle(mergeStyle, !mergeForm.value.canMergeNow); switchMergeStyle(mergeStyle, !mergeForm.canMergeNow);
document.addEventListener('mouseup', hideMergeStyleMenu); document.addEventListener('mouseup', hideMergeStyleMenu);
}); });
@ -63,7 +63,7 @@ function hideMergeStyleMenu() {
function toggleActionForm(show: boolean) { function toggleActionForm(show: boolean) {
showActionForm.value = show; showActionForm.value = show;
if (!show) return; if (!show) return;
deleteBranchAfterMerge.value = mergeForm.value.defaultDeleteBranchAfterMerge; deleteBranchAfterMerge.value = mergeForm.defaultDeleteBranchAfterMerge;
mergeTitleFieldValue.value = mergeStyleDetail.value.mergeTitleFieldText; mergeTitleFieldValue.value = mergeStyleDetail.value.mergeTitleFieldText;
mergeMessageFieldValue.value = mergeStyleDetail.value.mergeMessageFieldText; mergeMessageFieldValue.value = mergeStyleDetail.value.mergeMessageFieldText;
} }
@ -74,7 +74,7 @@ function switchMergeStyle(name: string, autoMerge = false) {
} }
function clearMergeMessage() { function clearMergeMessage() {
mergeMessageFieldValue.value = mergeForm.value.defaultMergeMessage; mergeMessageFieldValue.value = mergeForm.defaultMergeMessage;
} }
</script> </script>

View File

@ -1,9 +1,9 @@
<script lang="ts" setup> <script lang="ts" setup>
// @ts-expect-error - module exports no types // @ts-expect-error - module exports no types
import {VueBarGraph} from 'vue-bar-graph'; import {VueBarGraph} from 'vue-bar-graph';
import {computed, onMounted, ref} from 'vue'; import {computed, onMounted, shallowRef, useTemplateRef} from 'vue';
const colors = ref({ const colors = shallowRef({
barColor: 'green', barColor: 'green',
textColor: 'black', textColor: 'black',
textAltColor: 'white', textAltColor: 'white',
@ -41,8 +41,8 @@ const graphWidth = computed(() => {
return activityTopAuthors.length * 40; return activityTopAuthors.length * 40;
}); });
const styleElement = ref<HTMLElement | null>(null); const styleElement = useTemplateRef('styleElement');
const altStyleElement = ref<HTMLElement | null>(null); const altStyleElement = useTemplateRef('altStyleElement');
onMounted(() => { onMounted(() => {
const refStyle = window.getComputedStyle(styleElement.value); const refStyle = window.getComputedStyle(styleElement.value);

View File

@ -23,7 +23,7 @@ import {
import {chartJsColors} from '../utils/color.ts'; import {chartJsColors} from '../utils/color.ts';
import {sleep} from '../utils.ts'; import {sleep} from '../utils.ts';
import 'chartjs-adapter-dayjs-4/dist/chartjs-adapter-dayjs-4.esm'; import 'chartjs-adapter-dayjs-4/dist/chartjs-adapter-dayjs-4.esm';
import {onMounted, ref} from 'vue'; import {onMounted, shallowRef} from 'vue';
const {pageData} = window.config; const {pageData} = window.config;
@ -47,10 +47,10 @@ defineProps<{
}; };
}>(); }>();
const isLoading = ref(false); const isLoading = shallowRef(false);
const errorText = ref(''); const errorText = shallowRef('');
const repoLink = ref(pageData.repoLink || []); const repoLink = pageData.repoLink;
const data = ref<DayData[]>([]); const data = shallowRef<DayData[]>([]);
onMounted(() => { onMounted(() => {
fetchGraphData(); fetchGraphData();
@ -61,7 +61,7 @@ async function fetchGraphData() {
try { try {
let response: Response; let response: Response;
do { do {
response = await GET(`${repoLink.value}/activity/code-frequency/data`); response = await GET(`${repoLink}/activity/code-frequency/data`);
if (response.status === 202) { if (response.status === 202) {
await sleep(1000); // wait for 1 second before retrying await sleep(1000); // wait for 1 second before retrying
} }

View File

@ -21,7 +21,7 @@ import {
import {chartJsColors} from '../utils/color.ts'; import {chartJsColors} from '../utils/color.ts';
import {sleep} from '../utils.ts'; import {sleep} from '../utils.ts';
import 'chartjs-adapter-dayjs-4/dist/chartjs-adapter-dayjs-4.esm'; import 'chartjs-adapter-dayjs-4/dist/chartjs-adapter-dayjs-4.esm';
import {onMounted, ref} from 'vue'; import {onMounted, ref, shallowRef} from 'vue';
const {pageData} = window.config; const {pageData} = window.config;
@ -43,9 +43,9 @@ defineProps<{
}; };
}>(); }>();
const isLoading = ref(false); const isLoading = shallowRef(false);
const errorText = ref(''); const errorText = shallowRef('');
const repoLink = ref(pageData.repoLink || []); const repoLink = pageData.repoLink;
const data = ref<DayData[]>([]); const data = ref<DayData[]>([]);
onMounted(() => { onMounted(() => {
@ -57,7 +57,7 @@ async function fetchGraphData() {
try { try {
let response: Response; let response: Response;
do { do {
response = await GET(`${repoLink.value}/activity/recent-commits/data`); response = await GET(`${repoLink}/activity/recent-commits/data`);
if (response.status === 202) { if (response.status === 202) {
await sleep(1000); // wait for 1 second before retrying await sleep(1000); // wait for 1 second before retrying
} }

View File

@ -1,9 +1,9 @@
<script lang="ts" setup> <script lang="ts" setup>
import ViewFileTreeItem from './ViewFileTreeItem.vue'; import ViewFileTreeItem from './ViewFileTreeItem.vue';
import {onMounted, ref} from 'vue'; import {onMounted, useTemplateRef} from 'vue';
import {createViewFileTreeStore} from './ViewFileTreeStore.ts'; import {createViewFileTreeStore} from './ViewFileTreeStore.ts';
const elRoot = ref<HTMLElement | null>(null); const elRoot = useTemplateRef('elRoot');
const props = defineProps({ const props = defineProps({
repoLink: {type: String, required: true}, repoLink: {type: String, required: true},

View File

@ -1,7 +1,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import {SvgIcon} from '../svg.ts'; import {SvgIcon} from '../svg.ts';
import {isPlainClick} from '../utils/dom.ts'; import {isPlainClick} from '../utils/dom.ts';
import {ref} from 'vue'; import {shallowRef} from 'vue';
import {type createViewFileTreeStore} from './ViewFileTreeStore.ts'; import {type createViewFileTreeStore} from './ViewFileTreeStore.ts';
type Item = { type Item = {
@ -20,9 +20,9 @@ const props = defineProps<{
}>(); }>();
const store = props.store; const store = props.store;
const isLoading = ref(false); const isLoading = shallowRef(false);
const children = ref(props.item.children); const children = shallowRef(props.item.children);
const collapsed = ref(!props.item.children); const collapsed = shallowRef(!props.item.children);
const doLoadChildren = async () => { const doLoadChildren = async () => {
collapsed.value = !collapsed.value; collapsed.value = !collapsed.value;