Skip to content

Instantly share code, notes, and snippets.

@owenconti
Created February 10, 2021 19:56
Show Gist options
  • Save owenconti/37c9f2df5714b10a16d80f889d41d365 to your computer and use it in GitHub Desktop.
Save owenconti/37c9f2df5714b10a16d80f889d41d365 to your computer and use it in GitHub Desktop.
Why you should be using React Context more often
// inside ModalHeader component...
const ModalCloseButton = () => {
const {closeModal} = useModal();
return (
<button type="button" onClick={() => closeModal()}>X</button>
);
}
const ModalHeader = ({
title
}) => {
return (
<header>
{title}
<ModalCloseButton />
</header>
);
};
// inside your Modal component...
const Modal = ({
onClose
}) => {
const closeModal = useCallback(() => {
// Fake code, pretend to start the closing transition
// and call `onClose` when the transition is done
startCloseTransition(onClose);
}, [onClose]);
return (
<ModalContextProvider closeModal={closeModal}>
<ModalOverlay>
<ModalContent>
<ModalHeader />
<ModalBody>
{children}
</ModalBody>
</ModalContent>
</ModalOverlay>
</ModalContextProvider>
);
};
// No changes to `SomeComponent`...
const SomeComponent = () => {
const [modalOpen, setModalOpen] = useState(false);
return (
<div>
<button type="button" onClick={() => setModalOpen(true)}>Open Modal</button>
{modalOpen ? (
<Modal title="Some Modal" onClose={() => setModalOpen(false)}>
<SomeComponentModalContent />
</Modal>
) : null}
</div>
);
};
const SomeComponentModalContent = () => {
// `SomeComponentModalContent` has access to the modal context
const {closeModal} = useModal();
return (
<div>
<p>The content of the modal goes here</p>
<button type="button" onClick={() => closeModal()}>Close the modal</button>
</div>
);
};
// inside your Modal component...
const Modal = ({
title,
onClose
}) => {
const closeModal = useCallback(() => {
// Fake code, pretend to start the closing transition
// and call `onClose` when the transition is done
startCloseTransition(onClose);
}, [onClose]);
return (
<ModalOverlay closeModal={closeModal}>
<ModalContent>
<ModalHeader title={title} closeModal={closeModal} />
<ModalBody>
{React.cloneElement(children, { closeModal })}
</ModalBody>
</ModalContent>
</ModalOverlay>
);
};
// inside ModalOverlay component...
const ModalOverlay = ({
children
}) => {
const { closeModal } = useModal();
return (
<div onClick={() => closeModal()}>
{children}
</div>
);
};
const SomeComponent = () => {
const [modalOpen, setModalOpen] = useState(false);
return (
<div>
<button type="button" onClick={() => setModalOpen(true)}>Open Modal</button>
{modalOpen ? (
<Modal title="Some Modal" onClose={() => setModalOpen(false)}>
<SomeComponentModalContent />
</Modal>
) : null}
</div>
);
};
const SomeComponentModalContent = ({
closeModal
}) => {
// `closeModal` is available here because the `Modal`
// component passes it via the `cloneElement` call
return (
<div>
<p>The content of the modal goes here</p>
<button type="button" onClick={() => closeModal()}>Close the modal</button>
</div>
);
};
// modal context file...
export const ModalContext = React.createContext();
export const useModal = () => {
return useContext(ModalContext);
}
export const ModalContextProvider = ({ closeModal, children }) => {
const context = useMemo(() => {
return {
closeModal
};
}, [closeModal]);
return (
<ModalContext.Provider value={context}>{children}</ModalContext.Provider>
);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment