extra-react-hooks 0.8.9 → 0.8.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,29 +1,21 @@
1
- import { useState } from 'react';
1
+ import { useRef } from 'react';
2
2
  import { isntNaN } from 'extra-utils';
3
3
  import { useIIFE } from './use-iife.js';
4
+ import { useForceUpdate } from './use-force-update.js';
4
5
  export function useNumberInput({ value, lazy, onChange }) {
5
- const [displayValue, setDisplayValue] = useState(() => value.toString());
6
- useIIFE(() => {
7
- if (!lazy) {
8
- const oldValue = Number(displayValue);
9
- if (oldValue !== value)
10
- setDisplayValue(value.toString());
11
- }
12
- }, [lazy, value, displayValue]);
13
- useIIFE(() => {
14
- if (lazy) {
15
- setDisplayValue(value.toString());
16
- }
17
- }, [lazy, value]);
6
+ const [displayValue, setDisplayValue] = useDerivedState(value.toString());
18
7
  return {
19
8
  getInputProps() {
20
9
  return {
21
10
  type: 'number',
22
11
  value: displayValue,
23
12
  onChange(e) {
24
- setDisplayValue(e.target.value);
25
- if (e.target.reportValidity()) {
26
- if (!lazy) {
13
+ if (lazy) {
14
+ e.target.reportValidity();
15
+ setDisplayValue(e.target.value);
16
+ }
17
+ else {
18
+ if (e.target.reportValidity()) {
27
19
  const newValue = e.target.valueAsNumber;
28
20
  if (isntNaN(newValue) && newValue !== value) {
29
21
  onChange(newValue, false);
@@ -34,23 +26,36 @@ export function useNumberInput({ value, lazy, onChange }) {
34
26
  onBlur(e) {
35
27
  if (e.target.checkValidity()) {
36
28
  const newValue = e.target.valueAsNumber;
37
- if (!lazy || (isntNaN(newValue) && newValue !== value)) {
29
+ if (isntNaN(newValue) && newValue !== value) {
30
+ setDisplayValue(newValue.toString(), true);
38
31
  onChange(newValue, true);
39
- setDisplayValue(newValue.toString());
40
- return;
32
+ }
33
+ else {
34
+ setDisplayValue(value.toString(), true);
41
35
  }
42
36
  }
43
37
  else {
44
- if (!lazy) {
45
- onChange(value, true);
46
- setDisplayValue(value.toString());
47
- return;
48
- }
38
+ setDisplayValue(value.toString(), true);
49
39
  }
50
- setDisplayValue(value.toString());
51
40
  }
52
41
  };
53
42
  }
54
43
  };
55
44
  }
45
+ function useDerivedState(dep) {
46
+ const forceUpdate = useForceUpdate();
47
+ const stateRef = useRef(dep);
48
+ useIIFE(() => {
49
+ stateRef.current = dep;
50
+ }, [dep]);
51
+ return [
52
+ stateRef.current,
53
+ (newState, force = false) => {
54
+ if (force || stateRef.current !== newState) {
55
+ stateRef.current = newState;
56
+ forceUpdate();
57
+ }
58
+ }
59
+ ];
60
+ }
56
61
  //# sourceMappingURL=use-number-input.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-number-input.js","sourceRoot":"","sources":["../src/use-number-input.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAEvC,MAAM,UAAU,cAAc,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAKrD;IASC,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,CAAS,GAAG,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAA;IAEhF,OAAO,CAAC,GAAG,EAAE;QACX,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,QAAQ,GAAG,MAAM,CAAC,YAAY,CAAC,CAAA;YAGrC,IAAI,QAAQ,KAAK,KAAK;gBAAE,eAAe,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAA;QAC3D,CAAC;IACH,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC,CAAA;IAE/B,OAAO,CAAC,GAAG,EAAE;QACX,IAAI,IAAI,EAAE,CAAC;YAGT,eAAe,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAA;QACnC,CAAC;IACH,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAA;IAEjB,OAAO;QACL,aAAa;YACX,OAAO;gBACL,IAAI,EAAE,QAAQ;gBACd,KAAK,EAAE,YAAY;gBACnB,QAAQ,CAAC,CAAC;oBACR,eAAe,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;oBAE/B,IAAI,CAAC,CAAC,MAAM,CAAC,cAAc,EAAE,EAAE,CAAC;wBAC9B,IAAI,CAAC,IAAI,EAAE,CAAC;4BACV,MAAM,QAAQ,GAAG,CAAC,CAAC,MAAM,CAAC,aAAa,CAAA;4BAEvC,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,QAAQ,KAAK,KAAK,EAAE,CAAC;gCAC5C,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAA;4BAC3B,CAAC;wBACH,CAAC;oBACH,CAAC;gBACH,CAAC;gBACD,MAAM,CAAC,CAAC;oBACN,IAAI,CAAC,CAAC,MAAM,CAAC,aAAa,EAAE,EAAE,CAAC;wBAC7B,MAAM,QAAQ,GAAG,CAAC,CAAC,MAAM,CAAC,aAAa,CAAA;wBAEvC,IAAI,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,QAAQ,KAAK,KAAK,CAAC,EAAE,CAAC;4BACvD,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;4BAIxB,eAAe,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAA;4BAEpC,OAAM;wBACR,CAAC;oBACH,CAAC;yBAAM,CAAC;wBACN,IAAI,CAAC,IAAI,EAAE,CAAC;4BACV,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC,CAAA;4BAErB,eAAe,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAA;4BAEjC,OAAM;wBACR,CAAC;oBACH,CAAC;oBAGD,eAAe,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAA;gBACnC,CAAC;aACF,CAAA;QACH,CAAC;KACF,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"use-number-input.js","sourceRoot":"","sources":["../src/use-number-input.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAEtD,MAAM,UAAU,cAAc,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAKrD;IASC,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,eAAe,CAAS,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAA;IAEjF,OAAO;QACL,aAAa;YACX,OAAO;gBACL,IAAI,EAAE,QAAQ;gBACd,KAAK,EAAE,YAAY;gBAGnB,QAAQ,CAAC,CAAC;oBACR,IAAI,IAAI,EAAE,CAAC;wBACT,CAAC,CAAC,MAAM,CAAC,cAAc,EAAE,CAAA;wBAEzB,eAAe,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;oBACjC,CAAC;yBAAM,CAAC;wBACN,IAAI,CAAC,CAAC,MAAM,CAAC,cAAc,EAAE,EAAE,CAAC;4BAC9B,MAAM,QAAQ,GAAG,CAAC,CAAC,MAAM,CAAC,aAAa,CAAA;4BAEvC,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,QAAQ,KAAK,KAAK,EAAE,CAAC;gCAC5C,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAA;4BAC3B,CAAC;wBACH,CAAC;oBACH,CAAC;gBACH,CAAC;gBACD,MAAM,CAAC,CAAC;oBACN,IAAI,CAAC,CAAC,MAAM,CAAC,aAAa,EAAE,EAAE,CAAC;wBAC7B,MAAM,QAAQ,GAAG,CAAC,CAAC,MAAM,CAAC,aAAa,CAAA;wBAEvC,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,QAAQ,KAAK,KAAK,EAAE,CAAC;4BAC5C,eAAe,CAAC,QAAQ,CAAC,QAAQ,EAAE,EAAE,IAAI,CAAC,CAAA;4BAE1C,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;wBAC1B,CAAC;6BAAM,CAAC;4BACN,eAAe,CAAC,KAAK,CAAC,QAAQ,EAAE,EAAE,IAAI,CAAC,CAAA;wBACzC,CAAC;oBACH,CAAC;yBAAM,CAAC;wBACN,eAAe,CAAC,KAAK,CAAC,QAAQ,EAAE,EAAE,IAAI,CAAC,CAAA;oBACzC,CAAC;gBACH,CAAC;aACF,CAAA;QACH,CAAC;KACF,CAAA;AACH,CAAC;AAED,SAAS,eAAe,CAAI,GAAM;IAIhC,MAAM,WAAW,GAAG,cAAc,EAAE,CAAA;IACpC,MAAM,QAAQ,GAAG,MAAM,CAAI,GAAG,CAAC,CAAA;IAE/B,OAAO,CAAC,GAAG,EAAE;QACX,QAAQ,CAAC,OAAO,GAAG,GAAG,CAAA;IACxB,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAA;IAET,OAAO;QACL,QAAQ,CAAC,OAAO;QAChB,CAAC,QAAQ,EAAE,KAAK,GAAG,KAAK,EAAE,EAAE;YAC1B,IAAI,KAAK,IAAI,QAAQ,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;gBAC3C,QAAQ,CAAC,OAAO,GAAG,QAAQ,CAAA;gBAE3B,WAAW,EAAE,CAAA;YACf,CAAC;QACH,CAAC;KACF,CAAA;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "extra-react-hooks",
3
- "version": "0.8.9",
3
+ "version": "0.8.11",
4
4
  "description": "",
5
5
  "keywords": [],
6
6
  "files": [
@@ -1,6 +1,7 @@
1
- import { useState } from 'react'
1
+ import { useRef } from 'react'
2
2
  import { isntNaN } from 'extra-utils'
3
3
  import { useIIFE } from './use-iife.js'
4
+ import { useForceUpdate } from './use-force-update.js'
4
5
 
5
6
  export function useNumberInput({ value, lazy, onChange }: {
6
7
  value: number
@@ -16,35 +17,22 @@ export function useNumberInput({ value, lazy, onChange }: {
16
17
  | 'onBlur'
17
18
  >>
18
19
  } {
19
- const [displayValue, setDisplayValue] = useState<string>(() => value.toString())
20
-
21
- useIIFE(() => {
22
- if (!lazy) {
23
- const oldValue = Number(displayValue)
24
-
25
- // 以传入的值为准, 但只有在实际代表的值不同时, 才更新.
26
- if (oldValue !== value) setDisplayValue(value.toString())
27
- }
28
- }, [lazy, value, displayValue])
29
-
30
- useIIFE(() => {
31
- if (lazy) {
32
- // 以传入的值为准.
33
- // 由于onChange是惰性调用, 不需要检查值的相等性.
34
- setDisplayValue(value.toString())
35
- }
36
- }, [lazy, value])
20
+ const [displayValue, setDisplayValue] = useDerivedState<string>(value.toString())
37
21
 
38
22
  return {
39
23
  getInputProps() {
40
24
  return {
41
25
  type: 'number'
42
26
  , value: displayValue
27
+ // `input[type='number']`有一些特异行为:
28
+ // 如果只是在数字后面输入点`.`, 不会触发change事件.
43
29
  , onChange(e) {
44
- setDisplayValue(e.target.value)
30
+ if (lazy) {
31
+ e.target.reportValidity()
45
32
 
46
- if (e.target.reportValidity()) {
47
- if (!lazy) {
33
+ setDisplayValue(e.target.value)
34
+ } else {
35
+ if (e.target.reportValidity()) {
48
36
  const newValue = e.target.valueAsNumber
49
37
 
50
38
  if (isntNaN(newValue) && newValue !== value) {
@@ -57,29 +45,41 @@ export function useNumberInput({ value, lazy, onChange }: {
57
45
  if (e.target.checkValidity()) {
58
46
  const newValue = e.target.valueAsNumber
59
47
 
60
- if (!lazy || (isntNaN(newValue) && newValue !== value)) {
61
- onChange(newValue, true)
62
-
63
- // 使用格式化后的新值.
64
- // 若hook的调用方决定不接受新值, 则displayValue的值会被覆盖.
65
- setDisplayValue(newValue.toString())
48
+ if (isntNaN(newValue) && newValue !== value) {
49
+ setDisplayValue(newValue.toString(), true)
66
50
 
67
- return
51
+ onChange(newValue, true)
52
+ } else {
53
+ setDisplayValue(value.toString(), true)
68
54
  }
69
55
  } else {
70
- if (!lazy) {
71
- onChange(value, true)
72
-
73
- setDisplayValue(value.toString())
74
-
75
- return
76
- }
56
+ setDisplayValue(value.toString(), true)
77
57
  }
78
-
79
- // 继续使用旧值, 但对旧值格式化.
80
- setDisplayValue(value.toString())
81
58
  }
82
59
  }
83
60
  }
84
61
  }
85
62
  }
63
+
64
+ function useDerivedState<T>(dep: T): [
65
+ state: T
66
+ , setState: (newState: T, force?: boolean) => void
67
+ ] {
68
+ const forceUpdate = useForceUpdate()
69
+ const stateRef = useRef<T>(dep)
70
+
71
+ useIIFE(() => {
72
+ stateRef.current = dep
73
+ }, [dep])
74
+
75
+ return [
76
+ stateRef.current
77
+ , (newState, force = false) => {
78
+ if (force || stateRef.current !== newState) {
79
+ stateRef.current = newState
80
+
81
+ forceUpdate()
82
+ }
83
+ }
84
+ ]
85
+ }