'How can I run React with hooks in an iFrame

I am writing a React application in which I would like to dynamically render React components through an iFrame. I have a code editor on the webpage that allows users to write their React code, and I would like it to render that code into an iFrame embedded on the page.

This html (stored in htmlString) is passed directly into the iFrame through the its srcdoc.


<!DOCTYPE HTML>
    <html lang="en">
     <head> 
      <meta charset="utf-8">
      <title>My New Snippet</title>
    </head>
    
    <body>
      <div id="app"> </div>
    
      <script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
      <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
      <script type="application/javascript" src="https://unpkg.com/[email protected]/babel.js"></script>
      <script defer type="text/babel">
        console.log(React);
        const { useState } = React
    
        const App = (props) => { 
          const [text, setText] = useState('hello');
    
          return (
            <div>
              <h1>{text}</h1>
              <input type="text" value={text} onChange={(e) => setText(e.target.value)} />
            </div>
          );
        }
    
        ReactDOM.render(
          App(),
        document.getElementById('app')
        );
    
      </script>
    </body> 
  </html>

This is what the iFrame looks like in the render section of my component:


<iframe
  srcDoc={htmlString}
  width="100%"
  height="100%"
  title="output"
  sandbox="allow-scripts"
/>

When running the code, I get the following error:


Uncaught TypeError: Cannot read properties of null (reading 'useState')
    at useState (react.development.js:1610:23)
    at App (<anonymous>:12:19)
    at <anonymous>:31:17
    at run (babel.js:61531:11)
    at check (babel.js:61597:10)
    at loadScripts (babel.js:61638:4)
    at runScripts (babel.js:61668:4)
    at transformScriptTags (babel.js:336:40)
    at babel.js:327:13

To me, this looks like React is not defined in the context, but through console.logs, I was able to confirm that it does exist in the correct scope.



Solution 1:[1]

Try like this , ReactDOM.render is deprecated on React 18 version , you are included React 18 script.

<!DOCTYPE HTML>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>My New Snippet</title>
</head>

<body>
<div id="app"> </div>

<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
<script type="application/javascript" src="https://unpkg.com/[email protected]/babel.js"></script>
<script defer type="text/babel">
    console.log(React);
    const { useState } = React
    const { createRoot } = ReactDOM ;

    const App = (props) => {
        const [text, setText] = useState('hello');

        return (
            <div>
                <h1>{text}</h1>
                <input type="text" value={text} onChange={(e) => setText(e.target.value)} />
            </div>
        );
    }
    const container = document.getElementById('app');
    const root = createRoot(container);
    root.render(<App />);
</script>
</body>
</html>

Read more here DOC

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Hakob Sargsyan