-
Notifications
You must be signed in to change notification settings - Fork 20
/
Copy pathMap.tsx
92 lines (80 loc) · 2.37 KB
/
Map.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
import React, { ReactElement } from 'react'
import { useFacetMemo } from '../hooks/useFacetMemo'
import { useFacetUnwrap } from '../hooks/useFacetUnwrap'
import { useFacetMap } from '../hooks/useFacetMap'
import { EqualityCheck, Facet, NO_VALUE } from '../types'
export type MapProps<T> = {
array: Facet<T[]>
children: (item: Facet<T>, index: number, length: number) => ReactElement | null
equalityCheck?: EqualityCheck<T>
}
export const Map = <T,>({ array, children, equalityCheck }: MapProps<T>) => {
const lengthValue = useFacetUnwrap(useFacetMap((array) => array.length, [], [array]))
const lengthNumber = lengthValue !== NO_VALUE ? lengthValue : 0
return (
<>
{times(
(index) =>
equalityCheck !== undefined ? (
<MapChildMemo<T>
key={index}
arrayFacet={array}
index={index}
length={lengthNumber}
equalityCheck={equalityCheck}
children={children}
/>
) : (
<MapChild<T> key={index} arrayFacet={array} index={index} length={lengthNumber} children={children} />
),
lengthNumber,
)}
</>
)
}
type MapChildMemoProps<T> = {
arrayFacet: Facet<T[]>
index: number
length: number
children: (item: Facet<T>, index: number, length: number) => ReactElement | null
equalityCheck: EqualityCheck<T>
}
const MapChildMemo = <T,>({ arrayFacet, index, length, children, equalityCheck }: MapChildMemoProps<T>) => {
const childFacet = useFacetMemo(
(array) => {
if (index < array.length) return array[index]
return NO_VALUE
},
[index],
[arrayFacet],
equalityCheck,
)
return children(childFacet, index, length)
}
type MapChildProps<T> = {
arrayFacet: Facet<T[]>
index: number
length: number
children: (item: Facet<T>, index: number, length: number) => ReactElement | null
}
const MapChild = <T,>({ arrayFacet, index, length, children }: MapChildProps<T>) => {
const childFacet = useFacetMap(
(array) => {
if (index < array.length) return array[index]
return NO_VALUE
},
[index],
[arrayFacet],
)
return children(childFacet, index, length)
}
interface TimesFn<T> {
(index: number): T
}
const times = <T,>(fn: TimesFn<T>, n: number) => {
const result = []
for (let index = 0; index < n; index++) {
result.push(fn(index))
}
return result
}