I have the following situation:
What i'm doing now is this: I have a component that accepts a key as a props, and from a pre-defined map, i will know the component i want to render (using React.lazy()), modal title, and action button text. It works, but this way i have to use my child's function when the action button is clicked (for example with using ref) but i want to avoid this, since it's not the react way.
export function MyModal(props: MyModalProps) {
const {onClose, isOpen, key} = props;
// custom hook that gives me the details for the render (including the component with React.lazy)
const {
title, subtitle, Component, actionText, changeKey, nextKey
} = useModalRenderDetails(key);
const handleModalHide = (event) => {
onClose();
};
return (
<Modal
modalTitle={title}
modalSubtitle={subtitle}
mainActionLabel={actionText}
secondaryActionLabel={'Skip'}
open={isOpen}
onHide={event => handleModalHide(event)}
onMainAction={childHandlerFunctionFromRef}
onSecondaryAction={() => changeKey(nextKey)}
>
<React.Suspense fallback={<div>LOADING</div>}>
<Component/>
</React.Suspense>
</Modal>
);
}
can anyone provide a better solution for this situation? Feel free to suggest design changes if needed
This seems like a good usage of a context.
Consider placing the code below in a separate file and exporting only necessary items.
First of all, define a context:
const ConnectionContext = createContext();
Then create a custom provider to wrap the functions you need
const ConnectionContextProvider = ({ children }) => {
const action = useRef(null);
const setAction = (action) => {
action.current = action;
}
const removeAction = () => {
action.current = null;
}
const dispatchAction = () => {
action.current && action.current()
}
return (
<ConnectionContext.Provider
value={{
setAction,
removeAction,
dispatchAction,
}}
>
{children}
</ConnectionContext.Provider>
);
}
Then wrap the useContext (this step is optional)
const useConnectionContext = () => {
const context = useContext(context);
return context;
}
In the parent:
const MyModal = () => {
const { dispatchAction } = useConnectionContext()
// ...
return (
<Modal
// ...
onMainAction={dispatchAction}
>
// ...
</Modal>
)
}
In the child:
const Child = () => {
const { setAction, removeAction } = useConnectionContext()
useEffect(() => {
setAction(() => {
// the action you want to run
})
return () => removeAction()
}, [])
}
Have in mind that all code in this answer is untested.