Skip to content

Commit

Permalink
feat(useList): reimplemented useList hook;
Browse files Browse the repository at this point in the history
feat(useList): new action upsert;
feat(useList): new action update;
feat(useList): new action updateFirst;
feat(useList): new action insertAt;
feat(useList): action remove renamed to removeAt (ref remained);
feat(useUpsert): useUpsert hook deprecated cause of duplicate functionality and bad naming;
  • Loading branch information
xobotyi committed Nov 6, 2019
1 parent f094a3a commit 1840b57
Show file tree
Hide file tree
Showing 8 changed files with 584 additions and 218 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@
- [`useStateList`](./docs/useStateList.md) — circularly iterates over an array. [![][img-demo]](https://codesandbox.io/s/bold-dewdney-pjzkd)
- [`useToggle` and `useBoolean`](./docs/useToggle.md) — tracks state of a boolean. [![][img-demo]](https://codesandbox.io/s/focused-sammet-brw2d)
- [`useCounter` and `useNumber`](./docs/useCounter.md) — tracks state of a number. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/state-usecounter--demo)
- [`useList`](./docs/useList.md) and [`useUpsert`](./docs/useUpsert.md) — tracks state of an array. [![][img-demo]](https://codesandbox.io/s/wonderful-mahavira-1sm0w)
- [`useList`](./docs/useList.md) ~and [`useUpsert`](./docs/useUpsert.md)~ — tracks state of an array. [![][img-demo]](https://codesandbox.io/s/wonderful-mahavira-1sm0w)
- [`useMap`](./docs/useMap.md) — tracks state of an object. [![][img-demo]](https://codesandbox.io/s/quirky-dewdney-gi161)
- [`useStateValidator`](./docs/useStateValidator.md) — tracks state of an object. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/state-usestatevalidator--demo)
- [`useMultiStateValidator`](./docs/useMultiStateValidator.md) — alike the `useStateValidator`, but tracks multiple states at a time. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/state-usemultistatevalidator--demo)
Expand Down
45 changes: 43 additions & 2 deletions docs/useList.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
# `useList`

React state hook that tracks a value of an array.
Tracks an array and provides methods to modify it.
To cause component re-render you have to use these methods instead of direct interaction with array - it won't cause re-render.

We can ensure that actions object and actions itself will not mutate or change between renders, so there is no need to add it to useEffect dependencies and safe to pass them down to children.

**Note:** `remove` action is deprecated and actually is a copy of `removeAt` action. Within closest updates it will gain different functionality.

## Usage

```jsx
import {useList} from 'react-use';

const Demo = () => {
const [list, { clear, filter, push, remove, set, sort, updateAt, reset }] = useList();
const [list, { set, push, updateAt, insertAt, update, updateFirst, upsert, sort, filter, removeAt, clear, reset }] = useList([1, 2, 3, 4, 5]);

return (
<div>
Expand All @@ -27,6 +32,42 @@ const Demo = () => {
};
```

## Reference
```ts
import {useList} from "react-use";

const [list, {
set,
push,
updateAt,
insertAt,
update,
updateFirst,
upsert,
sort,
filter,
removeAt,
remove,
clear,
reset
}] = useList(array: any[] | ()=> any[]);
```

- **`list`**_`: T{}`_ &mdash; current list;
- **`set`**_`: (list: T[]) => void;`_ &mdash; Set new list instead old one;
- **`push`**_`: (...items: T[]) => void;`_ &mdash; Add item(s) at the end of list;
- **`updateAt`**_`: (index: number, item: T) => void;`_ &mdash; Replace item at given position. If item at given position not exists it will be set;
- **`insertAt`**_`: (index: number, item: T) => void;`_ &mdash; Insert item at given position, all items to the right will be shifted;
- **`update`**_`: (predicate: (a: T, b: T) => boolean, newItem: T) => void;`_ &mdash; Replace all items that matches predicate with given one;
- **`updateFirst`**_`: (predicate: (a: T, b: T) => boolean, newItem: T) => void;`_ &mdash; Replace first item matching predicate with given one;
- **`upsert`**_`: (predicate: (a: T, b: T) => boolean, newItem: T) => void;`_ &mdash; Like `updateFirst` bit in case of predicate miss - pushes item to the list;
- **`sort`**_`: (compareFn?: (a: T, b: T) => number) => void;`_ &mdash; Sort list with given sorting function;
- **`filter`**_`: (callbackFn: (value: T, index?: number, array?: T[]) => boolean, thisArg?: any) => void;`_ &mdash; Same as native Array's method;
- **`removeAt`**_`: (index: number) => void;`_ &mdash; Removes item at given position. All items to the right from removed will be shifted;
- **`remove`**_`: (index: number) => void;`_ &mdash; _**DEPRECATED:**_ Use removeAt method instead;
- **`clear`**_`: () => void;`_ &mdash; Make the list empty;
- **`reset`**_`: () => void;`_ &mdash; Reset list to initial value;

## Related hooks

- [useUpsert](./useUpsert.md)
3 changes: 3 additions & 0 deletions docs/useUpsert.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# `useUpsert`

> DEPRECATED!
> Use `useList` hook's upsert action instead
Superset of [`useList`](./useList.md). Provides an additional method to upsert (update or insert) an element into the list.

## Usage
Expand Down
54 changes: 51 additions & 3 deletions src/__stories__/useList.story.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,72 @@ import { useList } from '..';
import ShowDocs from './util/ShowDocs';

const Demo = () => {
const [list, { clear, filter, push, remove, set, sort, updateAt, reset }] = useList([1, 2, 3, 4, 5]);
const [list, { set, push, updateAt, insertAt, update, updateFirst, sort, filter, removeAt, clear, reset }] = useList([
1,
2,
3,
4,
5,
]);

return (
<div>
<button onClick={() => set([1, 2, 3])}>Set to [1, 2, 3]</button>
<br />
<button onClick={() => push(Date.now())}>Push timestamp</button>
<br />
<button onClick={() => insertAt(1, Date.now())}>Insert new value at index 1</button>
<br />
<button onClick={() => updateAt(1, Date.now())}>Update value at index 1</button>
<button onClick={() => remove(1)}>Remove element at index 1</button>
<br />
<button onClick={() => removeAt(1)}>Remove element at index 1</button>
<br />
<button onClick={() => filter(item => item % 2 === 0)}>Filter even values</button>
<br />
<button onClick={() => update(item => item % 2 === 0, Date.now())}>Update all even values with timestamp</button>
<br />
<button onClick={() => updateFirst(item => item % 2 === 0, Date.now())}>
Update first even value with timestamp
</button>
<br />
<button onClick={() => sort((a, b) => a - b)}>Sort ascending</button>
<br />
<button onClick={() => sort((a, b) => b - a)}>Sort descending</button>
<br />
<button onClick={clear}>Clear</button>
<br />
<button onClick={reset}>Reset</button>
<br />
<pre>{JSON.stringify(list, null, 2)}</pre>
</div>
);
};

interface UpsertDemoType {
id: string;
text: string;
}

const upsertPredicate = (a: UpsertDemoType, b: UpsertDemoType) => a.id === b.id;
const upsertInitialItems: UpsertDemoType[] = [{ id: '1', text: 'Sample' }, { id: '2', text: 'Example' }];
const UpsertDemo = () => {
const [list, { upsert, reset, removeAt }] = useList(upsertInitialItems);

return (
<div style={{ display: 'inline-flex', flexDirection: 'column' }}>
{list.map((item, index) => (
<div key={item.id}>
<input value={item.text} onChange={e => upsert(upsertPredicate, { ...item, text: e.target.value })} />
<button onClick={() => removeAt(index)}>Remove</button>
</div>
))}
<button onClick={() => upsert(upsertPredicate, { id: (list.length + 1).toString(), text: '' })}>Add item</button>
<button onClick={() => reset()}>Reset</button>
</div>
);
};

storiesOf('State|useList', module)
.add('Docs', () => <ShowDocs md={require('../../docs/useList.md')} />)
.add('Demo', () => <Demo />);
.add('Demo', () => <Demo />)
.add('Upsert Demo', () => <UpsertDemo />);
Loading

0 comments on commit 1840b57

Please sign in to comment.