I have a global component called <MyGlobalComponent/>
that resides in <App/>
. What I am trying to achieve is that I want to build a global function showGlobalComponent()
that can be called from any other component, one which sets its visibility and the content rendered inside it (which is another component).
MyGlobalComponent.tsx
export type GlobalComponentProps {
Component: React.FC
isVisible: boolean
};
export function showGlobalComponent ({Component, isVisible}: GlobalComponentProps) {
// ??? What do I do here ???
// Supposedly I'd set isVisible & ComponentToRender state variables here, but I can't, I'm outside the function
}
function MyGlobalComponent() {
const [ComponentToRender, setComponentToRender] = useState<React.FC | null>(null);
const [isVisible, setIsVisible] = useState<boolean>(false)
return (
<View style={APPSTYLE.myComponentStyle} />
{
isVisible &&
<>
ComponentToRender
</>
}
</View>
)
Here is the example of how I'd call it
AnotherComponent.tsx
function AnotherComponent() {
useEffect(() => {
showGlobalComponent({
isGlobalComponentVisible: true,
Component => <TertiaryComponent myProp="asds"/>
})
}, [])
}
I thought about using Redux and only memorizing a string associated with the component I want to render inside <MyGlobalComponent/> (because you cannot memoize non-serializable stuff with Redux). However, if I want to pass a prop to it like I did above to
TertiaryComponent`, that becomes quite impossible.
A solution I thought of (which I'm in doubt about) is using DeviceEventEmitter
from react-native
to emit an event and then listening to it inside an useEffect
in <MyGlobalComponent/>
MyGlobalComponent.tsx
export function showGlobalComponent (
{ Component, isVisible }: GlobalComponentProps
) {
DeviceEventEmitter.emit("myEventName", Component, isVisible);
}
// ...
useEffect(() => {
const myEvent = DeviceEventEmitter.addListener(
"myEventName",
({ Component, isVisible }: GlobalComponentProps) => {
setIsVisible(isVisible)
setComponentToRender(Component)
}
);
return () => {
myEvent.remove();
};
}, []);
However, the behaviour of this is inconsistent and this doesn't seem the right way to do it. Besides, DeviceEventEmitter
is very poorly documented.
What's a more common or practical way to achieve this?
Your code is not React-ing very correctly. Instead of declaring some unrestricted global and mutating it locally you should create a React Context provider to hold the state and provide the component and visibility value down to consumers.
Example:
MyGlobalComponentProvider.tsx
Import the
MyGlobalComponentProvider
component and wrap the app or root-level component to provide the context value to that sub-ReactTree. Consumers use the exporteduseMyGlobalComponentContext
hook to access the values and handle/render accordingly.App
AnotherComponent.tsx