Improve UI performance by optimizing reactivity

- Replace `ref`s with `shallowRef` when deep reactivity is not needed.
- Replace `readonly`s with `shallowReadonly` where the goal is to only
  prevent `.value` mutation.
- Remove redundant `ref` in `SizeObserver.vue`.
- Remove redundant nested `ref` in `TooltipWrapper.vue`.
- Remove redundant `events` export from `UseCollectionState.ts`.
- Remove redundant `computed` from `UseCollectionState.ts`.
- Remove `timestamp` from `TreeViewFilterEvent` that becomes unnecessary
  after using `shallowRef`.
- Add missing unit tests for `UseTreeViewFilterEvent`.
- Add missing stub for `FilterChangeDetails`.
This commit is contained in:
undergroundwires
2023-10-31 13:57:57 +01:00
parent 77123d8c92
commit 4995e49c46
24 changed files with 377 additions and 111 deletions

View File

@@ -1,6 +1,6 @@
import { describe, it, expect } from 'vitest';
import {
TreeViewFilterAction, TreeViewFilterEvent, TreeViewFilterPredicate,
TreeViewFilterAction, TreeViewFilterPredicate,
createFilterRemovedEvent, createFilterTriggeredEvent,
} from '@/presentation/components/Scripts/View/Tree/TreeView/Bindings/TreeInputFilterEvent';
@@ -47,19 +47,6 @@ describe('TreeViewFilterEvent', () => {
// expect
expect(event.predicate).to.equal(predicate);
});
it('returns unique timestamp', () => {
// arrange
const instances = new Array<TreeViewFilterEvent>();
// act
instances.push(
createFilterTriggeredEvent(createPredicateStub()),
createFilterTriggeredEvent(createPredicateStub()),
createFilterTriggeredEvent(createPredicateStub()),
);
// assert
const uniqueDates = new Set(instances.map((instance) => instance.timestamp));
expect(uniqueDates).to.have.length(instances.length);
});
});
describe('createFilterRemovedEvent', () => {
@@ -79,19 +66,6 @@ describe('TreeViewFilterEvent', () => {
// assert
expect(event.predicate).to.equal(expected);
});
it('returns unique timestamp', () => {
// arrange
const instances = new Array<TreeViewFilterEvent>();
// act
instances.push(
createFilterRemovedEvent(),
createFilterRemovedEvent(),
createFilterRemovedEvent(),
);
// assert
const uniqueDates = new Set(instances.map((instance) => instance.timestamp));
expect(uniqueDates).to.have.length(instances.length);
});
});
});

View File

@@ -1,6 +1,6 @@
import { describe, it, expect } from 'vitest';
import {
ref, defineComponent, WatchSource, nextTick,
shallowRef, defineComponent, WatchSource, nextTick,
} from 'vue';
import { shallowMount } from '@vue/test-utils';
import { ReadOnlyTreeNode } from '@/presentation/components/Scripts/View/Tree/TreeView/Node/TreeNode';
@@ -16,7 +16,7 @@ describe('useNodeState', () => {
it('should set state on immediate invocation if node exists', () => {
// arrange
const expectedState = new TreeNodeStateDescriptorStub();
const nodeWatcher = ref<ReadOnlyTreeNode | undefined>(undefined);
const nodeWatcher = shallowRef<ReadOnlyTreeNode | undefined>(undefined);
nodeWatcher.value = new TreeNodeStub()
.withState(new TreeNodeStateAccessStub().withCurrent(expectedState));
// act
@@ -27,7 +27,7 @@ describe('useNodeState', () => {
it('should not set state on immediate invocation if node is undefined', () => {
// arrange
const nodeWatcher = ref<ReadOnlyTreeNode | undefined>(undefined);
const nodeWatcher = shallowRef<ReadOnlyTreeNode | undefined>(undefined);
// act
const { returnObject } = mountWrapperComponent(nodeWatcher);
// assert
@@ -37,7 +37,7 @@ describe('useNodeState', () => {
it('should update state when nodeWatcher changes', async () => {
// arrange
const expectedNewState = new TreeNodeStateDescriptorStub();
const nodeWatcher = ref<ReadOnlyTreeNode | undefined>(undefined);
const nodeWatcher = shallowRef<ReadOnlyTreeNode | undefined>(undefined);
const { returnObject } = mountWrapperComponent(nodeWatcher);
// act
nodeWatcher.value = new TreeNodeStub()
@@ -49,7 +49,7 @@ describe('useNodeState', () => {
it('should update state when node state changes', () => {
// arrange
const nodeWatcher = ref<ReadOnlyTreeNode | undefined>(undefined);
const nodeWatcher = shallowRef<ReadOnlyTreeNode | undefined>(undefined);
const stateAccessStub = new TreeNodeStateAccessStub();
const expectedChangedState = new TreeNodeStateDescriptorStub();
nodeWatcher.value = new TreeNodeStub()

View File

@@ -1,6 +1,6 @@
import { describe, it, expect } from 'vitest';
import {
ref, defineComponent, WatchSource, nextTick,
shallowRef, defineComponent, WatchSource, nextTick,
} from 'vue';
import { shallowMount } from '@vue/test-utils';
import { TreeRoot } from '@/presentation/components/Scripts/View/Tree/TreeView/TreeRoot/TreeRoot';
@@ -15,7 +15,7 @@ describe('useCurrentTreeNodes', () => {
it('should set nodes on immediate invocation', () => {
// arrange
const expectedNodes = new QueryableNodesStub();
const treeWatcher = ref<TreeRoot>(new TreeRootStub().withCollection(
const treeWatcher = shallowRef<TreeRoot>(new TreeRootStub().withCollection(
new TreeNodeCollectionStub().withNodes(expectedNodes),
));
// act
@@ -27,7 +27,7 @@ describe('useCurrentTreeNodes', () => {
it('should update nodes when treeWatcher changes', async () => {
// arrange
const initialNodes = new QueryableNodesStub();
const treeWatcher = ref(
const treeWatcher = shallowRef(
new TreeRootStub().withCollection(new TreeNodeCollectionStub().withNodes(initialNodes)),
);
const { returnObject } = mountWrapperComponent(treeWatcher);
@@ -45,7 +45,7 @@ describe('useCurrentTreeNodes', () => {
// arrange
const initialNodes = new QueryableNodesStub();
const treeCollectionStub = new TreeNodeCollectionStub().withNodes(initialNodes);
const treeWatcher = ref(new TreeRootStub().withCollection(treeCollectionStub));
const treeWatcher = shallowRef(new TreeRootStub().withCollection(treeCollectionStub));
const { returnObject } = mountWrapperComponent(treeWatcher);