Skip to content

Commit 3272f80

Browse files
committed
v2
- More tests covering optimizations etc. - useMap for object API added - Separate import for every function - Two different import points for array API and object API - All typings are exported too for convenience of prop drilling etc. - Build process changed in favor of more manual, but simple approach - Rollup removed in favor of simple TS compilation - Prettier rules change - react-scripts removed in favor of just `jest` with `ts-jest`
1 parent 7ee9647 commit 3272f80

37 files changed

+9993
-13805
lines changed

.babelrc

Lines changed: 0 additions & 15 deletions
This file was deleted.

.eslintrc

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
11
{
2-
"extends": ["revolut-react"]
2+
"extends": [
3+
"revolut-react"
4+
],
5+
"rules": {
6+
"import/no-named-default": 0,
7+
"prettier/prettier": [
8+
1,
9+
{},
10+
{
11+
"usePrettierrc": true
12+
}
13+
]
14+
}
315
}

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,6 @@ dist
2323
npm-debug.log*
2424
yarn-debug.log*
2525
yarn-error.log*
26+
!/src/array/index.test.ts
27+
/main/
28+
/es6/

.prettierrc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"printWidth": 110,
3+
"semi": true,
4+
"singleQuote": true,
5+
"trailingComma": "all"
6+
}

README-ARRAY.md

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
## API Reference (array destructuring)
2+
3+
### How to import?
4+
5+
```
6+
import { useBoolean } from 'react-hanger/array' // will import all of functions
7+
import useBoolean from 'react-hanger/array/useBoolean' // will import only this function
8+
```
9+
10+
### useBoolean
11+
12+
```jsx
13+
const [showCounter, actions] = useBoolean(true);
14+
```
15+
16+
Actions:
17+
18+
- `toggle`
19+
- `setTrue`
20+
- `setFalse`
21+
22+
### useNumber
23+
24+
```jsx
25+
const [counter] = useNumber(0);
26+
const [limitedNumber] = useNumber(3, { upperLimit: 5, lowerLimit: 3 });
27+
const [rotatingNumber] = useNumber(0, {
28+
upperLimit: 5,
29+
lowerLimit: 0,
30+
loop: true
31+
});
32+
```
33+
34+
Actions:
35+
36+
Both `increase` and `decrease` take an optional `amount` argument which is 1 by default, and will override the `step` property if it's used in the options.
37+
38+
- `increase(amount = 1)`
39+
- `decrease(amount = 1 )`
40+
41+
Options:
42+
43+
- `lowerLimit`
44+
- `upperLimit`
45+
- `loop`
46+
- `step` - sets the increase/decrease amount of the number upfront, but it can still be overriden by `number.increase(3)` or `number.decrease(5)`
47+
48+
### useInput
49+
50+
This one is unique, since it returns tuple as a first element, where first element is `value` and second is `hasValue`
51+
Second element is `actions` as usual
52+
53+
```typescript
54+
type UseInputActions = {
55+
setValue: React.Dispatch<SetStateAction<string>>;
56+
onChange: (e: React.SyntheticEvent) => void
57+
clear: () => void
58+
}
59+
type UseInput = [[string, boolean], UseInputActions]
60+
```
61+
62+
```jsx
63+
const [[newTodo], actions] = useInput("");
64+
```
65+
66+
```jsx
67+
<input value={newTodo} onChange={actions.onChange} />
68+
```
69+
Actions:
70+
71+
- `clear`
72+
- `onChange` - default native event.target.value handler
73+
74+
Properties:
75+
76+
- `hasValue` -
77+
78+
### useBindToInput
79+
80+
Designed to be used in composition with `useInput`.
81+
First and second elements are the same as `useInput.
82+
Third are bindings to spread.
83+
84+
```jsx
85+
const [[newTodo], actions, { nativeBind, valueBind }] = useBindToInput(useInput(""));
86+
```
87+
88+
```jsx
89+
<input value={newTodo} onChange={actions.onChange} />
90+
<input {...nativeBind} />
91+
<Slider {...valueBind} />
92+
```
93+
94+
Actions:
95+
96+
- `nativeBind` - binds the `value` and `onChange` props to an input that has `e.target.value`
97+
- `valueBind` - binds the `value` and `onChange` props to an input that's using only `value` in `onChange` (like most external components)
98+
99+
### useArray
100+
101+
```jsx
102+
const [todos, actions] = useArray([]);
103+
```
104+
105+
Actions:
106+
107+
- `add`
108+
- `clear`
109+
- `removeIndex`
110+
- `removeById` - if array consists of objects with some specific `id` that you pass
111+
all of them will be removed
112+
- `move` - moves item from position to position shifting other elements.
113+
```
114+
So if input is [1, 2, 3, 4, 5]
115+
116+
from | to | expected
117+
3 | 0 | [4, 1, 2, 3, 5]
118+
-1 | 0 | [5, 1, 2, 3, 4]
119+
1 | -2 | [1, 3, 4, 2, 5]
120+
-3 | -4 | [1, 3, 2, 4, 5]
121+
```
122+
123+
### useMap
124+
125+
```jsx
126+
const [someMap, someMapActions] = useMap([["key", "value"]]);
127+
const [anotherMap, anotherMapActions] = useMap(new Map([["key", "value"]]));
128+
```
129+
130+
Actions:
131+
132+
- `set`
133+
- `remove`
134+
- `clear`
135+
- `initialize` - applies tuples or map instances
136+
- `setValue`
137+
138+
139+
## useSetState
140+
141+
```jsx
142+
const [state, setState] = useSetState({ loading: false });
143+
setState({ loading: true, data: [1, 2, 3] });
144+
```
145+
146+
Actions:
147+
148+
- `setState(value)` - will merge the `value` with the current `state` (like this.setState works in React)
149+
150+
Properties:
151+
152+
- `state` - the current state
153+
154+
## usePrevious
155+
156+
Use it to get the previous value of a prop or a state value.
157+
It's from the official [React Docs](https://reactjs.org/docs/hooks-faq.html#how-to-get-the-previous-props-or-state).
158+
It might come out of the box in the future.
159+
160+
```jsx
161+
const Counter = () => {
162+
const [count, setCount] = useState(0);
163+
const prevCount = usePrevious(count);
164+
return (
165+
<h1>
166+
Now: {count}, before: {prevCount}
167+
</h1>
168+
);
169+
};
170+
```
171+
172+
### Migration from object to array based
173+
174+
All value based hooks like `useBoolean`, `useNumber` etc. Are changed to
175+
be using arrays, since it's more safe for reference equality, and also
176+
makes it easier to use many `useSmth` without renaming `value` in destructuring.
177+
178+
So if you had
179+
```javascript
180+
const { value: showHeader, ...showHeaderActions } = useBoolean(true)
181+
const { value: showFooter, ...setShowFooterActions } = useBoolean(true)
182+
```
183+
It will become
184+
```javascript
185+
const [showHeader, showHeaderActions] = useBoolean(true)
186+
const [showFooter, showFooterActions] = useBoolean(true)
187+
```
188+
189+
Note that despite this code seems to be looking the same, it's not. Cause `showHeaderActions` in v1 will result
190+
in new object reference every rerender (because spreading creates new object, hence new reference). While in v2 actions are memoized
191+
using `useMemo` and their reference will not change, cause they are not rely on value.
192+
It enables us passing `actions` down the props without useless re-renders and excessive destructuring, it prevents `useEffects` and
193+
other hooks from re-run/new reference creation if autofix of ESLint rule `react-hooks/extraneous-deps` will add them as dependencies automatically.
194+
195+
### useInput migration
196+
Also big change to the `useInput`
197+
If before you was not using `eventBind` and `nativeBind` from them, then using the same approach from above
198+
you will get what you want.
199+
But if you need bindings you need to compose `useInput` with `useBindToInput` like that:
200+
So if you had
201+
```jsx
202+
const { value, eventBind, valueBind, onChange, hasValue } = useInput("")
203+
204+
<input value={value} onChange={onChange} />
205+
<input {...eventBind} />
206+
{hasValue && <Slider {...valueBind} />}
207+
```
208+
It will become
209+
```jsx
210+
const [[value, hasValue], actions, { eventBind, valueBind }] = useBindToInput(useInput(""))
211+
212+
<input value={value} onChange={actions.onChange} />
213+
<input {...eventBind} />
214+
{hasValue && <Slider {...valueBind} />}
215+
```
216+
217+
Note that first element in destructured array has tuple of `[value, hasValue]` since it's for values
218+
and second argument is for `actions` e.g. only for functions.

0 commit comments

Comments
 (0)