simbathesailor.DEV

Talk to React components from outside React

patterns
react-hook
usecallback
useref

August 06, 2020

Photo by stephen momot on Unsplash

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

Join the discussion