This repository has been archived by the owner on Aug 8, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
/
index.js
60 lines (50 loc) · 1.79 KB
/
index.js
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
import * as React from 'react'
const DescendantContext = React.createContext()
const randomId = () => Math.random().toString(36).substr(2, 9)
const noop = () => {}
const useLayout = typeof window === 'undefined' ? noop : React.useLayoutEffect
export const Descendants = (props) => {
// On every re-render of children, reset the count
props.value.reset()
return (
<DescendantContext.Provider value={props.value}>
{props.children}
</DescendantContext.Provider>
)
}
export const useDescendants = () => {
const indexCounter = React.useRef(0)
const map = React.useRef()
if (!map.current) map.current = {}
const reset = () => {
indexCounter.current = 0
map.current = {}
}
const get = (id, props) => {
const hidden = props ? props.hidden : false
if (!map.current[id])
map.current[id] = { index: hidden ? -1 : indexCounter.current++ }
map.current[id].props = props
return map.current[id].index
}
// Do NOT memoize context value, so that we bypass React.memo on any children
// We NEED them to re-render, in case stable children were re-ordered
// (this creates a new object every render, so children reading the context MUST re-render)
return { get, map, reset }
}
/**
* Return index of the current item within its parent's list
* @param {any} props - Props that will be exposed to the parent list
*/
export function useDescendant(props) {
const context = React.useContext(DescendantContext)
const descendantId = React.useRef()
if (!descendantId.current) descendantId.current = randomId()
const [index, setIndex] = React.useState(-1)
useLayout(() => {
// Do this inside of useLayoutEffect, it's only
// called for the "real render" in React strict mode
setIndex(context?.get(descendantId.current, props))
})
return index
}