Skip to content

Commit ec1f169

Browse files
committed
feat: add pop, shift, unshift, push to useArray
refactoring: reuse of Actions types in object version docs: added new APIs to the docs
1 parent ea9a5ab commit ec1f169

10 files changed

Lines changed: 61 additions & 55 deletions

File tree

README-ARRAY.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,10 @@ const [todos, actions] = useArray([]);
104104

105105
Actions:
106106

107-
- `add`
107+
- `push`
108+
- `unshift`
109+
- `pop`
110+
- `shift`
108111
- `clear`
109112
- `removeIndex`
110113
- `removeById` - if array consists of objects with some specific `id` that you pass
@@ -130,7 +133,7 @@ const [anotherMap, anotherMapActions] = useMap(new Map([["key", "value"]]));
130133
Actions:
131134

132135
- `set`
133-
- `remove`
136+
- `delete`
134137
- `clear`
135138
- `initialize` - applies tuples or map instances
136139
- `setValue`

README.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,10 @@ const todos = useArray([]);
163163

164164
Methods:
165165

166-
- `add`
166+
- `push` - similar to native doesn't return length tho
167+
- `unshift` - similar to native doesn't return length tho
168+
- `pop` - similar to native doesn't return element tho
169+
- `shift` - similar to native doesn't return element tho
167170
- `clear`
168171
- `removeIndex`
169172
- `removeById` - if array consists of objects with some specific `id` that you pass
@@ -189,7 +192,7 @@ const { value: anotherValue, remove } = useMap(new Map([["key", "value"]]));
189192
Actions:
190193

191194
- `set`
192-
- `remove`
195+
- `delete`
193196
- `clear`
194197
- `initialize` - applies tuples or map instances
195198
- `setValue`

src/array/index.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ describe('useArray array', () => {
165165
const [, actions] = result.current;
166166
expect(result.current[0].length).toBe(0);
167167

168-
act(() => actions.add('test'));
168+
act(() => actions.push('test'));
169169

170170
expect(result.current[0].length).toBe(1);
171171
});
@@ -236,7 +236,7 @@ describe('useArray array', () => {
236236
const [, originalActionsReference] = result.current;
237237
expect(result.current[1]).toBe(originalActionsReference);
238238
// when
239-
act(() => originalActionsReference.add(1));
239+
act(() => originalActionsReference.push(1));
240240
// then
241241
expect(originalActionsReference).toBe(result.current[1]);
242242
});
@@ -317,14 +317,14 @@ describe('useMap array', () => {
317317
});
318318
});
319319

320-
describe('remove', () => {
320+
describe('delete', () => {
321321
it('should delete existing value', () => {
322322
// given
323323
const { result } = renderHook(() => useMap<number, string>([[1, 'existing']]));
324324
const [, actions] = result.current;
325325
expect(result.current[0].get(1)).toBe('existing');
326326
// when
327-
act(() => actions.remove(1));
327+
act(() => actions.delete(1));
328328
// then
329329
expect(result.current[0].get(1)).toBeUndefined();
330330
});

src/array/useArray.ts

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@ import { UseStateful } from '../useStateful';
33

44
export type UseArrayActions<T> = {
55
setValue: UseStateful<T[]>['setValue'];
6-
add: (value: T) => void;
6+
add: (value: T | T[]) => void;
7+
push: (value: T | T[]) => void;
8+
pop: () => void;
9+
shift: () => void;
10+
unshift: (value: T | T[]) => void;
711
clear: () => void;
812
move: (from: number, to: number) => void;
913
removeById: (id: T extends { id: string } ? string : T extends { id: number } ? number : unknown) => void;
@@ -13,7 +17,12 @@ export type UseArray<T = any> = [T[], UseArrayActions<T>];
1317

1418
export function useArray<T = any>(initial: T[]): UseArray<T> {
1519
const [value, setValue] = useState(initial);
16-
const add = useCallback(a => setValue(v => [...v, a]), []);
20+
const push = useCallback(a => {
21+
setValue(v => [...v, ...(Array.isArray(a) ? a : [a])]);
22+
}, []);
23+
const unshift = useCallback(a => setValue(v => [...(Array.isArray(a) ? a : [a]), ...v]), []);
24+
const pop = useCallback(() => setValue(v => v.slice(0, -1)), []);
25+
const shift = useCallback(() => setValue(v => v.slice(1)), []);
1726
const move = useCallback(
1827
(from: number, to: number) =>
1928
setValue(it => {
@@ -41,14 +50,17 @@ export function useArray<T = any>(initial: T[]): UseArray<T> {
4150
const actions = useMemo(
4251
() => ({
4352
setValue,
44-
add,
45-
push: add,
53+
add: push,
54+
unshift,
55+
push,
4656
move,
4757
clear,
4858
removeById,
4959
removeIndex,
60+
pop,
61+
shift,
5062
}),
51-
[add, clear, move, removeById, removeIndex],
63+
[push, unshift, move, clear, removeById, removeIndex, pop, shift],
5264
);
5365
return [value, actions];
5466
}

src/array/useMap.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
import { Dispatch, SetStateAction, useCallback, useMemo, useState } from 'react';
22

33
export type MapOrEntries<K, V> = Map<K, V> | [K, V][];
4-
export type UseMapFunctions<K, V> = {
4+
export type UseMapActions<K, V> = {
55
setValue: Dispatch<SetStateAction<Map<K, V>>>;
66
remove: (keyToRemove: K) => void;
7+
delete: (keyToRemove: K) => void;
78
set: (key: K, value: V) => void;
89
clear: Map<K, V>['clear'];
910
initialize: (pairsOrMap: MapOrEntries<K, V>) => void;
1011
};
11-
export type UseMap<K, V> = [Map<K, V>, UseMapFunctions<K, V>];
12+
13+
export type UseMapFunctions<K, V> = UseMapActions<K, V>; // TODO: Remove on the next major release
14+
15+
export type UseMap<K, V> = [Map<K, V>, UseMapActions<K, V>];
1216

1317
export function useMap<K, V>(initialState: MapOrEntries<K, V> = new Map()): UseMap<K, V> {
1418
const [map, setMap] = useState(Array.isArray(initialState) ? new Map(initialState) : initialState);

src/index.test.ts

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -135,12 +135,14 @@ describe('useSetState', () => {
135135
});
136136

137137
describe('useArray', () => {
138-
it('should add item', () => {
138+
it('should push item', () => {
139139
const { result } = renderHook(() => useArray<string>([]));
140-
const { add } = result.current;
140+
const { push } = result.current;
141141
expect(result.current.value.length).toBe(0);
142142

143-
act(() => add('test'));
143+
act(() => {
144+
push('test');
145+
});
144146

145147
expect(result.current.value.length).toBe(1);
146148
});
@@ -208,12 +210,14 @@ describe('useArray', () => {
208210
it('should keep actions reference equality after value change', () => {
209211
// given
210212
const { result } = renderHook(() => useArray<any>([]));
211-
const { add } = result.current;
212-
expect(result.current.add).toBe(add);
213+
const { push } = result.current;
214+
expect(result.current.push).toBe(push);
213215
// when
214-
act(() => add(1));
216+
act(() => {
217+
push(1);
218+
});
215219
// then
216-
expect(add).toBe(result.current.add);
220+
expect(push).toBe(result.current.push);
217221
});
218222
});
219223
});
@@ -292,14 +296,14 @@ describe('useMap', () => {
292296
});
293297
});
294298

295-
describe('remove', () => {
299+
describe('delete', () => {
296300
it('should delete existing value', () => {
297301
// given
298302
const { result } = renderHook(() => useMap<number, string>([[1, 'existing']]));
299-
const { remove } = result.current;
303+
const { delete: aDelete } = result.current;
300304
expect(result.current.value.get(1)).toBe('existing');
301305
// when
302-
act(() => remove(1));
306+
act(() => aDelete(1));
303307
// then
304308
expect(result.current.value.get(1)).toBeUndefined();
305309
});

src/useArray.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,8 @@
11
import { useMemo } from 'react';
22
import { UseStateful } from './useStateful';
3-
import useArrayArray from './array/useArray';
3+
import useArrayArray, { UseArrayActions } from './array/useArray';
44

5-
export type UseArray<T> = UseStateful<T[]> & {
6-
add: (value: T) => void;
7-
clear: () => void;
8-
move: (from: number, to: number) => void;
9-
removeById: (id: T extends { id: string } ? string : T extends { id: number } ? number : unknown) => void;
10-
removeIndex: (index: number) => void;
11-
};
5+
export type UseArray<T> = UseStateful<T[]> & UseArrayActions<T>;
126

137
export function useArray<T = any>(initial: T[]): UseArray<T> {
148
const [value, actions] = useArrayArray(initial);

src/useBoolean.ts

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,8 @@
1-
import * as React from 'react';
2-
import { SetStateAction, useMemo } from 'react';
3-
import useBooleanArray from './array/useBoolean';
1+
import { useMemo } from 'react';
2+
import useBooleanArray, { UseBooleanActions } from './array/useBoolean';
3+
import { UseStateful } from './useStateful';
44

5-
export type UseBoolean = {
6-
value: boolean;
7-
setValue: React.Dispatch<SetStateAction<boolean>>;
8-
toggle: () => void;
9-
setTrue: () => void;
10-
setFalse: () => void;
11-
};
5+
export type UseBoolean = UseStateful<boolean> & UseBooleanActions;
126

137
export function useBoolean(initial: boolean): UseBoolean {
148
const [value, actions] = useBooleanArray(initial);

src/useMap.ts

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,9 @@
11
import { useMemo } from 'react';
22
import { UseStateful } from './useStateful';
3-
import useMapArray from './array/useMap';
3+
import useMapArray, { UseMapActions } from './array/useMap';
44

55
export type MapOrEntries<K, V> = Map<K, V> | [K, V][];
6-
export type UseMap<K, V> = UseStateful<Map<K, V>> & {
7-
remove: (keyToRemove: K) => void;
8-
set: (key: K, value: V) => void;
9-
clear: Map<K, V>['clear'];
10-
initialize: (pairsOrMap: MapOrEntries<K, V>) => void;
11-
};
6+
export type UseMap<K, V> = UseStateful<Map<K, V>> & UseMapActions<K, V>
127

138
export function useMap<K, V>(initialState: MapOrEntries<K, V> = new Map()): UseMap<K, V> {
149
const [map, actions] = useMapArray(initialState);

src/useNumber.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
import { useMemo } from 'react';
22
import { UseStateful } from './useStateful';
3-
import useNumberArray from './array/useNumber';
3+
import useNumberArray, { UseNumberActions } from './array/useNumber';
44

5-
export type UseNumber = UseStateful<number> & {
6-
increase: (value?: number) => void;
7-
decrease: (value?: number) => void;
8-
};
5+
export type UseNumber = UseStateful<number> & UseNumberActions;
96

107
export function useNumber(
118
initial: number,

0 commit comments

Comments
 (0)