Refactor watch sources for reliability

This commit changes `WatchSource` signatures into `Readonly<Ref>`s.

It provides two important benefits:

1. Eliminates the possibility of `undefined` states, that's result of
   using `WatchSource`s. This previously required additional null checks.
   By using `Readonly<Ref>`, the state handling becomes simpler and less
   susceptible to null errors.
2. Optimizes performance by using references:
   - Avoids the reactive layer of `computed` references when not needed.
   - The `watch` syntax, such as `watch(() => ref.value)`, can introduce
     side effects. For example, it does not account for `triggerRef` in
     scenarios where the value remains unchanged, preventing the watcher
     from running (vuejs/core#9579).
This commit is contained in:
undergroundwires
2023-11-11 13:55:21 +01:00
parent 58cd551a30
commit 7ab16ecccb
25 changed files with 190 additions and 217 deletions

View File

@@ -1,6 +1,5 @@
import {
WatchSource, computed,
ref, watch,
type Ref, computed, shallowReadonly,
} from 'vue';
import { ICategoryCollection } from '@/domain/ICategoryCollection';
import { injectKey } from '@/presentation/injectionSymbols';
@@ -10,7 +9,7 @@ import { convertToNodeInput } from './TreeNodeMetadataConverter';
import { parseSingleCategory, parseAllCategories } from './CategoryNodeMetadataConverter';
export function useTreeViewNodeInput(
categoryIdWatcher: WatchSource<number | undefined>,
categoryIdRef: Readonly<Ref<number | undefined>>,
parser: CategoryNodeParser = {
parseSingle: parseSingleCategory,
parseAll: parseAllCategories,
@@ -19,20 +18,14 @@ export function useTreeViewNodeInput(
) {
const { currentState } = injectKey((keys) => keys.useCollectionState);
const categoryId = ref<number | undefined>();
watch(categoryIdWatcher, (newCategoryId) => {
categoryId.value = newCategoryId;
}, { immediate: true });
const nodes = computed<readonly TreeInputNodeData[]>(() => {
const nodeMetadataList = parseNodes(categoryId.value, currentState.value.collection, parser);
const nodeMetadataList = parseNodes(categoryIdRef.value, currentState.value.collection, parser);
const nodeInputs = nodeMetadataList.map((node) => nodeConverter(node));
return nodeInputs;
});
return {
treeViewInputNodes: nodes,
treeViewInputNodes: shallowReadonly(nodes),
};
}