Skip to content

Commit

Permalink
add new test for computed that sorts an array
Browse files Browse the repository at this point in the history
I had a discussion with SEB and he told me about auto-sort compute. He said that
it would be better if we could implement automatic in-place sorting without
triggering the reactivity.

However, this PR can't actually handle that because this PR is just an extension
of the existing reactivity, it doesn't actually modify it. So if inplace sort
will result to multiple mutations, then that will be the number of times the
callback will be called. Even inside a `computed` that's introduced in this PR.

Nevertheless, compute that depends on sorted array is still useful, it's just
that the sorting should not be done in-place. This commit introduces an example
where a computed value that returns a sorted array is only called once (in a
batched context) even though multiple mutations are made to the array.
  • Loading branch information
caburj committed Jan 3, 2024
1 parent 51b2ea0 commit c38f021
Showing 1 changed file with 87 additions and 0 deletions.
87 changes: 87 additions & 0 deletions tests/computed.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,93 @@ describe("computed - with effect", () => {
expect(orderTotal).toEqual(244.8);
expectOrderComputeCounts({ itemTotal: 0, orderTotal: 1 });
});

test("computed sorted array", async () => {
let sortingCount = 0;
const expectSortingCount = (expected: number) => {
expect(sortingCount).toBe(expected);
sortingCount = 0;
};

const array = reactive([
52, 26, 71, 63, 72, 57, 71, 11, 17, 30, 52, 90, 14, 33, 86, 13, 62, 34, 99, 61, 21, 92, 95,
99, 0, 92, 6, 35, 95, 39, 87, 30, 50, 74, 21, 67, 34, 98, 99, 46, 85, 63, 41, 56, 18, 43, 23,
59, 52, 12,
]);

const sortedArray = computed((a: typeof array) => {
sortingCount++;
const copy = [...a];
return copy.sort((a, b) => a - b);
});

const range = computed((a: typeof array) => {
a = sortedArray(a);
return a[a.length - 1] - a[0];
});

const average = computed((a: typeof array) => {
let sum = 0;
for (let i = 0; i < a.length; i++) {
sum += a[i];
}
return Math.trunc(sum / a.length);
});

const min = computed((a: typeof array) => {
a = sortedArray(a);
return a[0];
});

const max = computed((a: typeof array) => {
a = sortedArray(a);
return a[a.length - 1];
});

const statTotal = computed((a: typeof array) => {
return range(a) + average(a) + min(a) + max(a);
});

let val = 0;
effect(
array,
batched((a) => {
val = statTotal(a) + statTotal(a) + statTotal(a);
})
);

await nextMicroTick();

expectSortingCount(1);
expect(val).toEqual(250 * 3);

array.push(99, 100);
await nextMicroTick();

expectSortingCount(1);
expect(val).toEqual(254 * 3);

array.push(-50);
await nextMicroTick();

expectSortingCount(1);
expect(val).toEqual(252 * 3);

// After some mutations, the original order is kept because the `sortedArray` getter makes a copy of the array before sorting.
const arrayCopy = [...array];
for (let i = 0; i < array.length; i++) {
expect(array[i]).toEqual(arrayCopy[i]);
}

// Sort will perform so many mutations in the original array.
// This will register several of recomputations.
// But since the effect is batched, it will only be recomputed once.
array.sort((a, b) => b - a);
await nextMicroTick();

expectSortingCount(1);
expect(val).toEqual(252 * 3);
});
});

describe("computed - with components", () => {
Expand Down

0 comments on commit c38f021

Please sign in to comment.