@ispb/react-lazy 0.0.4 → 0.0.6

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.
@@ -0,0 +1,39 @@
1
+ import { LazyEvent } from "./types.js";
2
+ export type LazyState<D> = {
3
+ readonly isLoading: true;
4
+ readonly isReloading: false;
5
+ readonly isSettled: false;
6
+ readonly isFulfilled: false;
7
+ readonly isRejected: false;
8
+ } | {
9
+ readonly isLoading: true;
10
+ readonly isReloading: true;
11
+ readonly isSettled: true;
12
+ readonly isFulfilled: true;
13
+ readonly isRejected: false;
14
+ readonly value: D;
15
+ } | {
16
+ readonly isLoading: true;
17
+ readonly isReloading: true;
18
+ readonly isSettled: true;
19
+ readonly isFulfilled: false;
20
+ readonly isRejected: true;
21
+ readonly reason: unknown;
22
+ readonly retry?: (() => void) | undefined;
23
+ } | {
24
+ readonly isLoading: false;
25
+ readonly isReloading: false;
26
+ readonly isSettled: true;
27
+ readonly isFulfilled: true;
28
+ readonly isRejected: false;
29
+ readonly value: D;
30
+ } | {
31
+ readonly isLoading: false;
32
+ readonly isReloading: false;
33
+ readonly isSettled: true;
34
+ readonly isFulfilled: false;
35
+ readonly isRejected: true;
36
+ readonly reason: unknown;
37
+ readonly retry?: (() => void) | undefined;
38
+ };
39
+ export declare function useLazyState<D>(current: LazyEvent<D>): LazyState<D>;
@@ -1,46 +1,6 @@
1
- import { usePrevious } from "./internal.js"
2
- import { LazyEvent, LazySettled } from "./types.js"
3
-
4
- export type LazyState<D> = {
5
- readonly isLoading: true
6
- readonly isReloading: false
7
- readonly isSettled: false
8
- readonly isFulfilled: false
9
- readonly isRejected: false
10
- } | {
11
- readonly isLoading: true
12
- readonly isReloading: true
13
- readonly isSettled: true
14
- readonly isFulfilled: true
15
- readonly isRejected: false
16
- readonly value: D
17
- } | {
18
- readonly isLoading: true
19
- readonly isReloading: true
20
- readonly isSettled: true
21
- readonly isFulfilled: false
22
- readonly isRejected: true
23
- readonly reason: unknown
24
- readonly retry?: (() => void) | undefined
25
- } | {
26
- readonly isLoading: false
27
- readonly isReloading: false
28
- readonly isSettled: true
29
- readonly isFulfilled: true
30
- readonly isRejected: false
31
- readonly value: D
32
- } | {
33
- readonly isLoading: false
34
- readonly isReloading: false
35
- readonly isSettled: true
36
- readonly isFulfilled: false
37
- readonly isRejected: true
38
- readonly reason: unknown
39
- readonly retry?: (() => void) | undefined
40
- }
41
-
42
- export function useLazyState<D>(current: LazyEvent<D>): LazyState<D> {
43
- const settled = usePrevious<LazySettled<D>>(current.status === "fulfilled" || current.status === "rejected" ? { current } : undefined)
1
+ import { usePrevious } from "./internal.js";
2
+ export function useLazyState(current) {
3
+ const settled = usePrevious(current.status === "fulfilled" || current.status === "rejected" ? { current } : undefined);
44
4
  if (current.status === "loading") {
45
5
  if (settled === undefined) {
46
6
  return {
@@ -49,7 +9,7 @@ export function useLazyState<D>(current: LazyEvent<D>): LazyState<D> {
49
9
  isSettled: false,
50
10
  isFulfilled: false,
51
11
  isRejected: false,
52
- }
12
+ };
53
13
  }
54
14
  else {
55
15
  if (settled.status === "fulfilled") {
@@ -60,7 +20,7 @@ export function useLazyState<D>(current: LazyEvent<D>): LazyState<D> {
60
20
  isFulfilled: true,
61
21
  isRejected: false,
62
22
  value: settled.value,
63
- }
23
+ };
64
24
  }
65
25
  else {
66
26
  return {
@@ -71,7 +31,7 @@ export function useLazyState<D>(current: LazyEvent<D>): LazyState<D> {
71
31
  isRejected: true,
72
32
  reason: settled.reason,
73
33
  retry: settled.retry,
74
- }
34
+ };
75
35
  }
76
36
  }
77
37
  }
@@ -83,7 +43,7 @@ export function useLazyState<D>(current: LazyEvent<D>): LazyState<D> {
83
43
  isFulfilled: true,
84
44
  isRejected: false,
85
45
  value: current.value,
86
- }
46
+ };
87
47
  }
88
48
  else {
89
49
  return {
@@ -94,6 +54,7 @@ export function useLazyState<D>(current: LazyEvent<D>): LazyState<D> {
94
54
  isRejected: true,
95
55
  reason: current.reason,
96
56
  retry: current.retry,
97
- }
57
+ };
98
58
  }
99
59
  }
60
+ //# sourceMappingURL=state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.js","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAyC3C,MAAM,UAAU,YAAY,CAAI,OAAqB;IACjD,MAAM,OAAO,GAAG,WAAW,CAAiB,OAAO,CAAC,MAAM,KAAK,WAAW,IAAI,OAAO,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;IACtI,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAC/B,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YACxB,OAAO;gBACH,SAAS,EAAE,IAAI;gBACf,WAAW,EAAE,KAAK;gBAClB,SAAS,EAAE,KAAK;gBAChB,WAAW,EAAE,KAAK;gBAClB,UAAU,EAAE,KAAK;aACpB,CAAA;QACL,CAAC;aACI,CAAC;YACF,IAAI,OAAO,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;gBACjC,OAAO;oBACH,SAAS,EAAE,IAAI;oBACf,WAAW,EAAE,IAAI;oBACjB,SAAS,EAAE,IAAI;oBACf,WAAW,EAAE,IAAI;oBACjB,UAAU,EAAE,KAAK;oBACjB,KAAK,EAAE,OAAO,CAAC,KAAK;iBACvB,CAAA;YACL,CAAC;iBACI,CAAC;gBACF,OAAO;oBACH,SAAS,EAAE,IAAI;oBACf,WAAW,EAAE,IAAI;oBACjB,SAAS,EAAE,IAAI;oBACf,WAAW,EAAE,KAAK;oBAClB,UAAU,EAAE,IAAI;oBAChB,MAAM,EAAE,OAAO,CAAC,MAAM;oBACtB,KAAK,EAAE,OAAO,CAAC,KAAK;iBACvB,CAAA;YACL,CAAC;QACL,CAAC;IACL,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;QACjC,OAAO;YACH,SAAS,EAAE,KAAK;YAChB,WAAW,EAAE,KAAK;YAClB,SAAS,EAAE,IAAI;YACf,WAAW,EAAE,IAAI;YACjB,UAAU,EAAE,KAAK;YACjB,KAAK,EAAE,OAAO,CAAC,KAAK;SACvB,CAAA;IACL,CAAC;SACI,CAAC;QACF,OAAO;YACH,SAAS,EAAE,KAAK;YAChB,WAAW,EAAE,KAAK;YAClB,SAAS,EAAE,IAAI;YACf,WAAW,EAAE,KAAK;YAClB,UAAU,EAAE,IAAI;YAChB,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,KAAK,EAAE,OAAO,CAAC,KAAK;SACvB,CAAA;IACL,CAAC;AACL,CAAC"}
@@ -0,0 +1,64 @@
1
+ import { ReactNode } from "react";
2
+ export type LazyLoading = {
3
+ readonly status: "loading";
4
+ };
5
+ export type LazyFulfilled<D> = {
6
+ readonly status: "fulfilled";
7
+ readonly value: D;
8
+ };
9
+ export type LazyRejected = {
10
+ readonly status: "rejected";
11
+ readonly reason: unknown;
12
+ readonly retry?: (() => () => void) | undefined;
13
+ };
14
+ export type LazySettled<D> = LazyFulfilled<D> | LazyRejected;
15
+ export type LazyEvent<D> = LazySettled<D> | LazyLoading;
16
+ export type OnLoading = (props: LoadingProps) => ReactNode;
17
+ export type OnReloading = (props: ReloadingProps) => ReactNode;
18
+ export type OnError = (props: ErrorProps) => ReactNode;
19
+ type LazyMeta = string;
20
+ export interface LoadingProps {
21
+ /**
22
+ * The message to display.
23
+ */
24
+ readonly message?: LazyMeta | undefined;
25
+ }
26
+ export interface ReloadingProps {
27
+ /**
28
+ * Whether or not the data is currently reloading.
29
+ */
30
+ readonly reloading: boolean;
31
+ /**
32
+ * The message to display.
33
+ */
34
+ readonly message?: LazyMeta | undefined;
35
+ /**
36
+ * The children.
37
+ */
38
+ readonly children: ReactNode;
39
+ }
40
+ export interface ErrorProps {
41
+ /**
42
+ * The error.
43
+ */
44
+ readonly reason: unknown;
45
+ /**
46
+ * The message to display.
47
+ */
48
+ readonly message?: LazyMeta | undefined;
49
+ }
50
+ export interface LazyOptions {
51
+ readonly onLoading?: OnLoading | undefined;
52
+ readonly onReloading?: OnReloading | undefined;
53
+ readonly onError?: OnError | undefined;
54
+ readonly defaultMessage?: LazyMeta | undefined;
55
+ readonly loadingMessage?: LazyMeta | undefined;
56
+ readonly reloadingMessage?: LazyMeta | undefined;
57
+ readonly errorMessage?: LazyMeta | undefined;
58
+ }
59
+ /**
60
+ * Overrides for lazy options.
61
+ */
62
+ export type LazyOverrides = Partial<LazyOptions>;
63
+ export type ExtractLazy<T> = T extends LazyFulfilled<infer D> ? D : never;
64
+ export {};
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.tsx"],"names":[],"mappings":""}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ispb/react-lazy",
3
- "version": "0.0.4",
3
+ "version": "0.0.6",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -8,6 +8,9 @@
8
8
  "build": "tsc",
9
9
  "watch": "tsc --watch"
10
10
  },
11
+ "files": [
12
+ "dist"
13
+ ],
11
14
  "exports": {
12
15
  "default": "./dist/index.js",
13
16
  "types": "./dist/index.d.ts"
@@ -24,6 +27,5 @@
24
27
  "@types/react": "^19.2.18",
25
28
  "react": "^19.2.8",
26
29
  "typescript": "^7.0.2"
27
- },
28
- "packageManager": "yarn@4.18.0"
30
+ }
29
31
  }
package/.yarnrc.yml DELETED
@@ -1,8 +0,0 @@
1
- approvedGitRepositories:
2
- - "**"
3
-
4
- enableScripts: true
5
-
6
- nodeLinker: node-modules
7
-
8
- npmMinimalAgeGate: 0
package/src/async.tsx DELETED
@@ -1,124 +0,0 @@
1
-
2
- import { ReactNode, useCallback, useEffect, useState } from "react"
3
- import { ValueOrFactory, callOrGet } from "value-or-factory"
4
- import { Lazy } from "./components.js"
5
- import { LazyHOCOptions, lazified } from "./hoc.js"
6
- import { useIsFirstMount } from "./internal.js"
7
- import { LazyState } from "./state.js"
8
- import { LazyEvent, LazyOverrides } from "./types.js"
9
-
10
- /**
11
- * Options for the async hook.
12
- * @typeParam D The data type.
13
- */
14
- export interface AsyncLazyOptions<D> {
15
-
16
- /**
17
- * A promise or a function that returns a promise. This MUST be memoized - the function will re-run every time a new value is received.
18
- */
19
- readonly promise: ValueOrFactory<PromiseLike<D>>
20
-
21
- /**
22
- * Don't execute immediately.
23
- */
24
- readonly defer?: AsyncLazyDefer<D> | undefined
25
-
26
- }
27
-
28
- export interface AsyncLazyDefer<D> {
29
-
30
- /**
31
- * The initial value to provide.
32
- */
33
- readonly initial: D
34
-
35
- }
36
-
37
- export type AsyncLazyEvent<D> = LazyEvent<D> & { readonly retry: Retry }
38
-
39
- export function useAsyncLazy<D>(input: AsyncLazyOptions<D> | (() => PromiseLike<D>)): AsyncLazyEvent<D> {
40
- const options = typeof input === "function" ? { promise: input } : input
41
- const [event, setEvent] = useState<LazyEvent<D>>(options.defer === undefined ? { status: "loading" } : { status: "fulfilled", value: options.defer.initial })
42
- const run = useCallback(() => {
43
- callOrGet(options.promise).then(value => {
44
- setEvent({
45
- status: "fulfilled",
46
- value,
47
- })
48
- }, reason => {
49
- setEvent({
50
- status: "rejected",
51
- reason,
52
- })
53
- })
54
- }, [
55
- options.promise
56
- ])
57
- const retry = useCallback((suppressReload = false) => {
58
- if (!suppressReload) {
59
- setEvent({
60
- status: "loading"
61
- })
62
- }
63
- run()
64
- }, [
65
- run
66
- ])
67
- const isFirstMount = useIsFirstMount()
68
- useEffect(() => {
69
- if (isFirstMount) {
70
- if (options.defer !== undefined) {
71
- return
72
- }
73
- }
74
- else {
75
- setEvent({
76
- status: "loading"
77
- })
78
- }
79
- run()
80
- }, [
81
- run,
82
- ])
83
- return {
84
- ...event,
85
- retry
86
- }
87
- }
88
-
89
- export type AsyncLazyState<D> = LazyState<D> & { readonly retry: Retry }
90
-
91
- export interface AsyncifiedOptions<D, P> extends AsyncLazyOptions<D>, LazyHOCOptions<AsyncLazyState<D>, P> {
92
- }
93
-
94
- export function asyncified<I extends {}, D extends {}, P extends {}>(factory: (props: I) => AsyncifiedOptions<D, P>) {
95
- return lazified((props: I) => {
96
- const options = factory(props)
97
- const event = useAsyncLazy(options)
98
- return {
99
- event,
100
- passthrough: state => callOrGet(options.passthrough, { ...state, retry: event.retry }),
101
- overrides: options.overrides,
102
- }
103
- })
104
- }
105
-
106
- export type Retry = (suppressReload?: boolean | undefined) => void
107
-
108
- export interface AsyncifiedProps<D> extends AsyncLazyOptions<D> {
109
-
110
- readonly children: ValueOrFactory<ReactNode, [D, AsyncLazyState<D>]>
111
-
112
- /**
113
- * The lazy overrides.
114
- */
115
- readonly overrides?: LazyOverrides | undefined
116
-
117
- }
118
-
119
- export const Asyncified = <D,>(props: AsyncifiedProps<D>) => {
120
- const event = useAsyncLazy(props)
121
- return <Lazy event={event}
122
- overrides={props.overrides}
123
- children={(value, state) => callOrGet(props.children, value, { ...state, retry: event.retry })} />
124
- }
@@ -1,46 +0,0 @@
1
-
2
- import { PropsWithChildren, ReactNode, useContext } from "react"
3
- import { LazyContext } from "./hooks.js"
4
- import { LazyState, useLazyState } from "./state.js"
5
- import { LazyEvent, LazyOverrides } from "./types.js"
6
-
7
- export interface LazyProps<D> {
8
-
9
- readonly event: LazyEvent<D>
10
- readonly overrides?: LazyOverrides | undefined
11
- readonly children: ReactNode | ((value: D, state: LazyState<D>) => ReactNode)
12
-
13
- }
14
-
15
- export function Lazy<D>(props: LazyProps<D>): ReactNode {
16
- const context = useContext(LazyContext)
17
- const options = { ...context, ...props.overrides }
18
- const state = useLazyState(props.event)
19
- if (state.isLoading && !state.isSettled) {
20
- if (options.onLoading === undefined) {
21
- return null
22
- }
23
- return options.onLoading({
24
- message: options.loadingMessage ?? options.defaultMessage
25
- })
26
- }
27
- const onReloading = options.onReloading ?? ((props: PropsWithChildren) => props.children)
28
- return onReloading({
29
- reloading: state.isLoading,
30
- message: options.reloadingMessage ?? options.defaultMessage,
31
- children: (() => {
32
- if (state.isRejected) {
33
- if (options.onError === undefined) {
34
- throw state.reason
35
- }
36
- return options.onError({
37
- reason: state.reason,
38
- message: options.errorMessage ?? options.defaultMessage,
39
- })
40
- }
41
- else {
42
- return typeof props.children === "function" ? props.children(state.value, state) : props.children
43
- }
44
- })()
45
- })
46
- }
package/src/hoc.tsx DELETED
@@ -1,37 +0,0 @@
1
-
2
- import { ComponentType, createElement } from "react"
3
- import { callOrGet, ValueOrFactory } from "value-or-factory"
4
- import { Lazy } from "./components.js"
5
- import { LazyState } from "./state.js"
6
- import { LazyEvent, LazyOverrides } from "./types.js"
7
-
8
- export interface LazyBuilder<D, P> extends LazyHOCOptions<LazyState<D>, P> {
9
-
10
- readonly event: LazyEvent<D>
11
-
12
- }
13
-
14
- export function lazified<I extends {}, D extends {}, P extends {}>(build: (props: I) => LazyBuilder<D, P>) {
15
- return (component: ComponentType<D & P>) => {
16
- return (props: I) => {
17
- const built = build(props)
18
- return <Lazy event={built.event}
19
- overrides={built.overrides}
20
- children={(value, state) => createElement(component, { ...callOrGet(built.passthrough, state), ...value })} />
21
- }
22
- }
23
- }
24
-
25
- export interface LazyHOCOptions<S, P> {
26
-
27
- /**
28
- * Properties to pass through to the component.
29
- */
30
- readonly passthrough: ValueOrFactory<P, [S]>
31
-
32
- /**
33
- * Overrides for lazy settings.
34
- */
35
- readonly overrides?: LazyOverrides | undefined
36
-
37
- }
package/src/hooks.ts DELETED
@@ -1,155 +0,0 @@
1
- import pDefer from "p-defer"
2
- import { createContext, useEffect, useMemo, useState } from "react"
3
- import { Observable, Subject } from "rxjs"
4
- import { useIsFirstMount } from "./internal.js"
5
- import { ExtractLazy, LazyEvent, LazyFulfilled, LazyLoading, LazyOverrides, LazyRejected } from "./types.js"
6
-
7
- export const LazyContext = createContext<LazyOverrides>({})
8
-
9
- export function isLoading<T>(event: LazyEvent<T>): event is LazyLoading {
10
- if (event.status === "loading") {
11
- return true
12
- }
13
- else {
14
- return false
15
- }
16
- }
17
- export function isFulfilled<T>(event: LazyEvent<T>): event is LazyFulfilled<T> {
18
- if (event.status === "fulfilled") {
19
- return true
20
- }
21
- else {
22
- return false
23
- }
24
- }
25
- export function isRejected<T>(event: LazyEvent<T>): event is LazyRejected {
26
- if (event.status === "rejected") {
27
- return true
28
- }
29
- else {
30
- return false
31
- }
32
- }
33
-
34
- export function useLazyFlatten<O>(event: LazyEvent<LazyEvent<O>>,) {
35
- return useLazyChain(event, event => event)
36
- }
37
- export function useLazyChain<I, O>(event: LazyEvent<I>, map: (value: I) => LazyEvent<O>) {
38
- return useMemo(() => {
39
- if (event.status === "fulfilled") {
40
- return map(event.value)
41
- }
42
- else {
43
- return event
44
- }
45
- }, [
46
- event
47
- ])
48
- }
49
- export function useLazyMap<I, O>(event: LazyEvent<I>, map: (value: I) => O) {
50
- return useMemo(() => {
51
- if (event.status === "fulfilled") {
52
- return {
53
- status: "fulfilled" as const,
54
- value: map(event.value)
55
- }
56
- }
57
- else {
58
- return event
59
- }
60
- }, [
61
- event
62
- ])
63
- }
64
-
65
- export function useObservableAsPromise<T>(observable: Observable<T>) {
66
- const [promise, setPromise] = useState(() => pDefer<T>())
67
- const isFirstMount = useIsFirstMount()
68
- useEffect(() => {
69
- if (!isFirstMount) {
70
- setPromise(pDefer<T>())
71
- }
72
- }, [
73
- observable
74
- ])
75
- useEffect(() => {
76
- const sub = observable.subscribe({
77
- next: value => {
78
- promise.resolve(value)
79
- },
80
- error: reason => {
81
- promise.reject(reason)
82
- }
83
- })
84
- return () => {
85
- sub.unsubscribe()
86
- }
87
- }, [
88
- promise
89
- ])
90
- return promise.promise
91
- }
92
-
93
- export function useLazyAsPromise<T>(event: LazyEvent<T>) {
94
- const [promise, setPromise] = useState(() => pDefer<T>())
95
- useEffect(() => {
96
- if (event.status === "fulfilled") {
97
- promise.resolve(event.value)
98
- }
99
- else if (event.status === "rejected") {
100
- promise.reject(event.reason)
101
- }
102
- else {
103
- setPromise(pDefer<T>())
104
- }
105
- }, [
106
- event
107
- ])
108
- return promise.promise
109
- }
110
-
111
- export function useLazyAsObservable<T>(event: LazyEvent<T>) {
112
- const subject = useMemo(() => new Subject<T>(), [])
113
- useEffect(() => {
114
- if (event.status === "fulfilled") {
115
- subject.next(event.value)
116
- }
117
- else if (event.status === "rejected") {
118
- subject.error(event.reason)
119
- }
120
- }, [
121
- event
122
- ])
123
- return subject
124
- }
125
-
126
- export function useLazyCombine<T extends Record<string, LazyEvent<unknown>>>(lazies: T): LazyEvent<{ [K in keyof T]: ExtractLazy<T[K]> }> {
127
- const entries = Object.entries(lazies)
128
- if (entries.map(entry => entry[1]).some(isLoading)) {
129
- return {
130
- status: "loading" as const,
131
- }
132
- }
133
- else {
134
- const failed = entries.map(entry => entry[1]).filter(isRejected).at(0)
135
- if (failed !== undefined) {
136
- return {
137
- status: "rejected" as const,
138
- reason: failed
139
- }
140
- }
141
- else {
142
- return {
143
- status: "fulfilled",
144
- value: Object.fromEntries(
145
- entries.map(([key, value]) => {
146
- return [
147
- key,
148
- value.status === "fulfilled" ? value.value : undefined,
149
- ] as const
150
- })
151
- ) as { [K in keyof T]: ExtractLazy<T[K]> }
152
- }
153
- }
154
- }
155
- }
package/src/index.tsx DELETED
@@ -1,9 +0,0 @@
1
-
2
- export * from "./async.js"
3
- export * from "./components.js"
4
- export * from "./hoc.js"
5
- export * from "./hooks.js"
6
- export * from "./observable.js"
7
- export * from "./state.js"
8
- export * from "./types.js"
9
-
package/src/internal.ts DELETED
@@ -1,21 +0,0 @@
1
- import { useRef } from "react"
2
-
3
- export function useIsFirstMount() {
4
- const isFirst = useRef(true)
5
- if (isFirst.current) {
6
- isFirst.current = false
7
- return true
8
- }
9
- return isFirst.current
10
- }
11
-
12
- export function usePrevious<T>(value: { readonly current: T } | undefined) {
13
- const previous = useRef(value?.current)
14
- const first = useIsFirstMount()
15
- if (!first) {
16
- if (value !== undefined) {
17
- previous.current = value.current
18
- }
19
- }
20
- return previous.current
21
- }