Last active
August 12, 2024 14:16
-
-
Save icedcrow/c0a43e0a2d898333416f2dba47a86bee to your computer and use it in GitHub Desktop.
react-native multiple modal
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
import { createContext, useContext, useState } from 'react'; | |
export function useStackModalContextCreator() { | |
const [list, setList] = useState([]); | |
const [stack, setStack] = useState([]); | |
const [hasRenderEntry, setHasRenderEntry] = useState(false); | |
return { list, setList, stack, setStack, hasRenderEntry, setHasRenderEntry }; | |
} | |
export const StackModalContext = createContext(null); | |
/** | |
* @returns {ReturnType<typeof useStackModalContextCreator>} | |
*/ | |
export function useStackModalContext() { | |
return useContext(StackModalContext); | |
} |
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
export { StackModal } from './StackModal'; | |
export { StackModalProvider } from './StackModalProvider'; | |
export { StackModalRenderEntry } from './StackModalRenderEntry'; |
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
import React, { useEffect, useRef } from 'react'; | |
import { useStackModalContext } from './context'; | |
/** | |
* @typedef {import('react-native').ModalProps} ModalProps | |
* @param {ModalProps} props | |
*/ | |
export function StackModal(props) { | |
const {visible} = props; | |
const {setList, setStack} = useStackModalContext(); | |
const componentIdRef = useRef(`${Math.random()}`); | |
useEffect(() => { | |
const componentId = componentIdRef.current; | |
setList((prev) => [...prev, {id: componentId, props}]); | |
return () => { | |
setList((prev) => prev.filter(({id}) => id !== componentId)); | |
}; | |
}, [setList, props]); | |
useEffect(() => { | |
const componentId = componentIdRef.current; | |
if (visible) { | |
setStack((prev) => [...prev, componentId]); | |
} | |
return () => { | |
setStack((prev) => prev.filter((id) => id !== componentId)); | |
}; | |
}, [setStack, visible]); | |
return null; | |
} |
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
import React from 'react'; | |
import { StackModalContext, useStackModalContextCreator } from './context'; | |
import {StackModalRenderEntryInternal} from './StackModalRenderEntry.internal'; | |
/** | |
* @param {import('react').PropsWithChildren} props | |
*/ | |
export function StackModalProvider(props) { | |
const context = useStackModalContextCreator(); | |
const {hasRenderEntry} = context; | |
return ( | |
<StackModalContext.Provider value={context}> | |
{props.children} | |
{!hasRenderEntry ? <StackModalRenderEntryInternal /> : null} | |
</StackModalContext.Provider> | |
); | |
} |
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
import React from 'react'; | |
import {useStackModalContext} from './context'; | |
import {Wrapper} from './Wrapper'; | |
export function StackModalRenderEntryInternal() { | |
const {list, stack} = useStackModalContext(); | |
const firstId = stack[0]; | |
const firstItem = firstId ? list.find(({id}) => id === firstId) : null; | |
return firstItem ? <Wrapper componentId={firstId} {...firstItem.props} /> : null; | |
} |
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
import React, {useEffect} from 'react'; | |
import {useStackModalContext} from './context'; | |
import {StackModalRenderEntryInternal} from './StackModalRenderEntry.internal'; | |
/** | |
* @param {{context?: ReturnType<import('./context').useStackModalContext>}} props | |
*/ | |
export function StackModalRenderEntry(props) { | |
const {context: incomeContext} = props; | |
const defaultContext = useStackModalContext(); | |
const context = incomeContext || defaultContext; | |
const {setHasRenderEntry} = context; | |
useEffect(() => { | |
setHasRenderEntry(true); | |
return () => { | |
setHasRenderEntry(false); | |
}; | |
}, [setHasRenderEntry]); | |
return <StackModalRenderEntryInternal />; | |
} |
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
import React from 'react'; | |
import { Modal } from 'react-native'; | |
import { useStackModalContext } from './context'; | |
/** | |
* @typedef {import('react-native').ModalProps} ModalProps | |
* @param {ModalProps & {componentId: string}} props | |
*/ | |
export function Wrapper(props) { | |
const {children, componentId, ...restProps} = props; | |
const {list, stack} = useStackModalContext(); | |
const index = stack.findIndex((v) => v === componentId); | |
const nextId = index >= 0 ? stack[index + 1] : null; | |
const nextItem = nextId ? list.find(({id}) => id === nextId) : null; | |
return ( | |
<Modal {...props}> | |
{children} | |
{nextItem ? <Wrapper componentId={nextId} {...nextItem.props} /> : null} | |
</Modal> | |
); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
May cause the components inside to detach from the external context.
The first solution is to move inside SomeContext.
Another solution is to re-establish a context within and pass the external context through to the internal context.
Or use to specify the location where will be rendered.