Talk to React components from outside React
August 06, 2020
What if I have to control the react components from non-react
codebases ? Let me re-phrase it with some concrete scenario.
What if I need to open a react modal from non-react codebase like utils functions, fetch wrapper e.t.c
This is such a common use case. We want to show the modal, then and there , when some condition passes. That condition can be in a non-react codebase.
Let see how we can do it.
All the modern applications, make use ES6 modules and they have live bindings. These live binding can be really useful when accessed from other files (any file react component or outside react component)
What is a live binding can be understood quickly by seeing the answer to this stackoverflow question.
Make sure you understand the above stackoverflow answer before diving ahead.
As we asked the question in context of a modal in the start, let’s start with some modal code.
import React from "react" | |
import Modal from "components/Modal" | |
import styled, { css } from "styled-components" | |
import { Button } from "components" | |
import PropTypes from "prop-types" | |
const MessageContainer = styled.div` | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
flex-direction: column; | |
height: 200px; | |
` | |
const MessageContent = styled.div` | |
margin-bottom: 24px; | |
` | |
const bodyStyles = css` | |
padding: 0; | |
overflow: auto; | |
background: #f8f8f8; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
flex-direction: column; | |
padding: 0px 30px; | |
` | |
// eslint-disable-next-line | |
let toggleModal = () => {} | |
function ModalFromOutsideReact(props) { | |
const [show, setShow] = React.useState(false) | |
const [data, setData] = React.useState(null) | |
toggleModal = (showVal, dataFromAPI) => { | |
setData(dataFromAPI) | |
setShow(showVal) | |
} | |
return ( | |
<> | |
<Modal | |
id="portal-root" | |
show={show} | |
bodyStyles={bodyStyles} | |
closeModal={() => { | |
setShow(false) | |
}} | |
> | |
<MessageContainer> | |
<MessageContent> | |
{data?.message || | |
"Content out of sync, Please refresh the browser window"} | |
</MessageContent> | |
<Button | |
onClick={() => { | |
window.location.reload() | |
}} | |
btnType="primary" | |
> | |
Reload | |
</Button> | |
</MessageContainer> | |
</Modal> | |
</> | |
) | |
} | |
ModalFromOutsideReact.propTypes = {} | |
export { toggleModal } | |
export default ModalFromOutsideReact |
Modal component is a not important here as it is a usual modal making use of react portal.
But notice , line no. 30, where I have declared and defined a variable toggleModal
outside ModalFromOutsideReact
. The component ModalFromOutsideReact
has the access to the toggleModal
from inside the component (Javascript closures at play here) and I can also change the value of toggle modal from inside the component.
So on the every re-render of this component, we can update the toggleModal with some state setter (or anything).
But in this example we can set it to the function below, which takes care of toggling the modal show/unshow
toggleModal = (showVal, dataFromAPI) => {
setData(dataFromAPI) // ignore this part
setShow(showVal)
}
Now whenever the show
value is truthy in the components, modal will show up.
We need 2 more steps to achieve our goal
We need to add this components somewhere in the APP react hirerarchy , possibly at the very top in this specific case.
Let’s say I have App.js which is at the very top in the App React hirerarchy.
I can safely render the ModalFromOutsideReact
component unconditionally here
Rendering in the App.js will make sure that the toggleModal
is instantiated
before any other component gets render in our App
App.js
import ModalFromOutsideReact from "path/to/ModalFromOutsideReact"
function App() {
return (
<div>
<ModalFromOutsideReact />
// Rest of the APP
</div>
)
}
Secondly we need to export the toggleModal
from ModalFromOutsideReact
. See the line no. 70 in github gist
Now, you are all set to trigger the modal from anywhere in the app, be it React component, non-react codebases like fetch wrappers, utils e.t.c.
You are not forced to go through all your component render cycle to show a modal. you can declaratively do that now.
This example is pretty basic and can be improved a lot. But the core idea was to demonstrate the how’s of interaction between react and non react world.
Thanks
Feel free to connect with me on https://twitter.com/simbatheesailor