Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Feat: Create separete hooks and context to handle descendants
- Loading branch information
1 parent
50c3a0b
commit 9dd8699
Showing
3 changed files
with
106 additions
and
38 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
import { | ||
createContext, | ||
ReactNode, | ||
useCallback, | ||
useContext, | ||
useRef, | ||
useState, | ||
} from "react"; | ||
import { useIsomorphicLayoutEffect } from "./useIsomorphicEffect.ts"; | ||
|
||
const randomId = () => Math.random().toString(36).substring(2, 9); | ||
|
||
const DescendantContext = createContext<DescendantProviderProps>( | ||
{} as DescendantProviderProps | ||
); | ||
|
||
export const Descendants = ({ | ||
children, | ||
value, | ||
}: { | ||
children: ReactNode; | ||
value: DescendantProviderProps; | ||
}) => { | ||
// On every re-render of children, reset the count | ||
value.reset(); | ||
|
||
return ( | ||
<DescendantContext.Provider value={value}> | ||
{children} | ||
</DescendantContext.Provider> | ||
); | ||
}; | ||
|
||
export const useDescendants = () => { | ||
const indexCounter = useRef(0); | ||
const map = useRef<Record<string, any>>({}); | ||
|
||
const getIndex = useCallback((id: string, props?: IgetIndexProps) => { | ||
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; | ||
}, []); | ||
|
||
// reset the counter and map | ||
const reset = useCallback(() => { | ||
indexCounter.current = 0; | ||
map.current = {}; | ||
}, []); | ||
|
||
return { getIndex, 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 const useDescendant = (props?: Record<string, any>) => { | ||
const context = useContext(DescendantContext); | ||
const descendantId = useRef<string>(); | ||
if (!descendantId.current) { | ||
descendantId.current = randomId(); | ||
} | ||
|
||
const [index, setIndex] = useState(-1); | ||
|
||
useIsomorphicLayoutEffect(() => { | ||
setIndex(context?.getIndex(descendantId.current as string, props)); | ||
}, []); | ||
|
||
return index; | ||
}; | ||
|
||
type DescendantProviderProps = ReturnType<typeof useDescendants>; | ||
|
||
interface IgetIndexProps { | ||
hidden?: boolean; | ||
|
||
[key: string]: any; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { useEffect, useLayoutEffect } from "react"; | ||
|
||
/* | ||
useLayoutEffect is a browser hook, so for React code generated from the server it will give error. | ||
For more details check: https://usehooks-ts.com/react-hook/use-isomorphic-layout-effect | ||
*/ | ||
export const useIsomorphicLayoutEffect = | ||
typeof window !== "undefined" ? useLayoutEffect : useEffect; |