Skip to content

Commit 045a6f6

Browse files
Issue #39 Port over useSortAlphabetically reducer hook
Add use-sorted-alphabetically.ts
2 parents 4b9f62b + c1c5d56 commit 045a6f6

3 files changed

Lines changed: 124 additions & 0 deletions

File tree

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import { render } from "@testing-library/react";
2+
import React from "react";
3+
import { act } from "react-dom/test-utils";
4+
import { useSortedAlphabetically } from "./use-sorted-alphabetically";
5+
6+
describe("useSortedAlphabetically", () => {
7+
const testSelector = (s: string) => s;
8+
9+
test("when initialState is not sorted, then returns sorted array", () => {
10+
// Arrange
11+
const unsortedList = ["C", "A", "D", "B"];
12+
const sortedList = ["A", "B", "C", "D"];
13+
14+
const TestApp = () => {
15+
const [values, setValues] = useSortedAlphabetically(
16+
unsortedList,
17+
testSelector
18+
);
19+
20+
return (
21+
<React.Fragment>
22+
{values.map((value: string) => (
23+
<p key={value} title="item">
24+
{value}
25+
</p>
26+
))}
27+
</React.Fragment>
28+
);
29+
};
30+
31+
// Act
32+
const { getAllByTitle } = render(<TestApp />);
33+
const items = getAllByTitle("item").map(
34+
(el: HTMLElement) => el.innerHTML
35+
);
36+
37+
// Assert
38+
expect(items).toStrictEqual(sortedList);
39+
});
40+
41+
test("when setValues is called with unsorted array, then values is set to a sorted array", () => {
42+
// Arrange
43+
const unsortedList = ["C", "A", "D", "B"];
44+
const sortedList = ["A", "B", "C", "D"];
45+
46+
const TestApp = () => {
47+
const [values, setValues] = useSortedAlphabetically(
48+
[],
49+
testSelector
50+
);
51+
52+
return (
53+
<React.Fragment>
54+
{values.map((value: string) => (
55+
<p key={value} title="item">
56+
{value}
57+
</p>
58+
))}
59+
<button
60+
onClick={() => setValues(unsortedList)}
61+
title="testButton"
62+
type="button"
63+
/>
64+
</React.Fragment>
65+
);
66+
};
67+
68+
// Act
69+
const { getAllByTitle, getByTitle } = render(<TestApp />);
70+
const button = getByTitle("testButton");
71+
act(() => button.click());
72+
const items = getAllByTitle("item").map(
73+
(el: HTMLElement) => el.innerHTML
74+
);
75+
76+
// Assert
77+
expect(items).toStrictEqual(sortedList);
78+
});
79+
});
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { CollectionUtils } from "andculturecode-javascript-core";
2+
import {
3+
Dispatch,
4+
Reducer,
5+
ReducerAction,
6+
ReducerState,
7+
useReducer,
8+
} from "react";
9+
10+
// -----------------------------------------------------------------------------------------
11+
// #region Hook
12+
// -----------------------------------------------------------------------------------------
13+
14+
/**
15+
* Create a stateful array value which is always sorted alphabetically.
16+
* @param initialValue the initial value of the array. Does not need to be sorted, the hook will sort it before setting the value.
17+
* @param sortBySelector a function which takes an array element, and returns a string property by which to sort alphabetically.
18+
*/
19+
function useSortedAlphabetically<T>(
20+
initialValue: Array<T>,
21+
sortBySelector: (value: T) => string
22+
): [
23+
ReducerState<Reducer<Array<T>, Array<T>>>,
24+
Dispatch<ReducerAction<Reducer<Array<T>, Array<T>>>>
25+
] {
26+
const [values, setValues] = useReducer<Reducer<Array<T>, Array<T>>>(
27+
// first parameter prevState is unused, replace with discard _
28+
(_: Array<T>, newState: Array<T>) =>
29+
CollectionUtils.sortByString(newState, sortBySelector),
30+
CollectionUtils.sortByString(initialValue, sortBySelector)
31+
);
32+
33+
return [values, setValues];
34+
}
35+
36+
// #endregion Hook
37+
38+
// -----------------------------------------------------------------------------------------
39+
// #region Exports
40+
// -----------------------------------------------------------------------------------------
41+
42+
export { useSortedAlphabetically };
43+
44+
// #endregion Exports

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export { useDebounce } from "./hooks/use-debounce";
3333
export { useLocalization } from "./hooks/use-localization";
3434
export { useOnClickOutside } from "./hooks/use-onclick-outside";
3535
export { usePageErrors } from "./hooks/use-page-errors";
36+
export { useSortedAlphabetically } from "./hooks/use-sorted-alphabetically";
3637
export { useTextOverflow } from "./hooks/use-text-overflow";
3738
export { useWindow } from "./hooks/use-window";
3839

0 commit comments

Comments
 (0)