Skip to content

Instantly share code, notes, and snippets.

@finom
Created October 3, 2023 11:49
Show Gist options
  • Save finom/0908a7390ca7946203f52fa7ba6e7da4 to your computer and use it in GitHub Desktop.
Save finom/0908a7390ca7946203f52fa7ba6e7da4 to your computer and use it in GitHub Desktop.
Allows to create portals within react components
import React, {
createContext,
useState,
useContext,
ReactNode,
FunctionComponent,
Dispatch,
SetStateAction,
} from 'react';
// Define a type for the shared state context
interface PortalContextProps<T> {
props: T | null;
setProps: Dispatch<SetStateAction<T | null>>;
}
// Create a context with an initial value of undefined
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const PortalContext = createContext<PortalContextProps<any> | undefined>(undefined);
export default function createComponentPortal<T>() {
const Provider: FunctionComponent<{ children: ReactNode }> = ({ children }) => {
const [props, setProps] = useState<T | null>(null);
return <PortalContext.Provider value={{ props, setProps }}>{children}</PortalContext.Provider>;
};
const Manipulator: FunctionComponent<T> = (props) => {
const context = useContext(PortalContext);
if (context) context.setProps(props); // Update the shared state when Manipulator receives new props
return null; // Render nothing
};
const Renderer: FunctionComponent<{ children: (props: T) => ReactNode }> = ({ children }) => {
const context = useContext(PortalContext);
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
if (context && context.props) return children(context.props); // Render the children function with the shared props
return null; // Render nothing if no props have been set yet
};
return { Provider, Manipulator, Renderer };
}
/*
// Usage:
const { Provider, Manipulator, Renderer } = createComponentPortal<{ message: string }>();
function App() {
return (
<Provider>
<Renderer>{(props) => <div {...props}>{props.message}</div>}</Renderer>
<Manipulator message="Hello World" />
</Provider>
);
}
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment