'Do react hooks work via CDN links in a simple single html file?

What is wrong with the following html & js, I can't use hooks! ... this is the only file in my project (no other files or package managers)

<html>
<body>
    <div id="root"></div>
    <script src="https://unpkg.com/react@17/umd/react.development.js" crossorigin ></script>
    <script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js" crossorigin ></script>
    <script>
        function Component() {
            React.useEffect(() => console.log('Hooks are working!!'))
            return React.createElement('h1', null, 'Hello World')
        }
        ReactDOM.render(Component(), document.getElementById('root'))
    </script>
</body>
</html>

I get the following error in the browser console (you can reproduce it just by copying the html in a index.html file and double clicking it):

react.development.js:1501 Uncaught Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.
    at resolveDispatcher (react.development.js:1501)
    at Object.useEffect (react.development.js:1544)
    at Component (index.html:8)
    at index.html:11
resolveDispatcher   @   react.development.js:1501
useEffect   @   react.development.js:1544
Component   @   index.html:8
(anonymous) @   index.html:11

If I comment out React.useEffect(() => console.log('Hooks are working!!')) it works ... but no react hooks :(



Solution 1:[1]

React.createElement needs to be used not only for the h1, but also for the whole container - the Component. Doing Component() doesn't let React differentiate it from a plain function call (and so doesn't permit a hook call inside) - pass Component into createElement instead:

<div id="root"></div>
<script src="https://unpkg.com/react@17/umd/react.development.js" crossorigin ></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js" crossorigin ></script>
<script>
    function Component() {
        React.useEffect(() => console.log('Hooks are working!!'))
        return React.createElement('h1', null, 'Hello World')
    }
    ReactDOM.render(React.createElement(Component), document.getElementById('root'))
</script>

Solution 2:[2]

In fact, it's not necessary to use createElement for the component too. Adding the MIME type and using an alternative right syntax also works:


<div id="root"> This will be changed</div>

<script type="text/babel">
  function Component() {
      React.useEffect(() => console.log('Hooks are working!!'))
      return React.createElement('h3', null, 'Hello World')
  }
  ReactDOM.render(<Component />, document.getElementById('root'))
</script>

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 CertainPerformance
Solution 2 Jony