Search code examples
reactjstypescriptreact-hooksreact-tsx

Cant use react hooks with typescript


Im using typescript to compile source tsx files to js.

The source code in the tsx file uses react hooks correctly, the compiled version appears to use them correctly too.

Source code (tsx)

import React, { useEffect } from "react";

export function Checkbox() : JSX.Element {
    useEffect(function() {
        console.log("Component mounted!");
    });

    return (
        <div>...</div>
    );
}

Compiles to (js)

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Checkbox = void 0;
var jsx_runtime_1 = require("react/jsx-runtime");
var react_1 = require("react");
function Checkbox() {
    react_1.useEffect(function () {
        console.log("Component mounted!");
    });
    return (jsx_runtime_1.jsx("div", { children: "..." }, void 0));
}
exports.Checkbox = Checkbox;
//# sourceMappingURL=Checkbox.js.map

tsconfig.json

{
    "$schema": "http://json.schemastore.org/tsconfig",
    "compilerOptions": {
        "lib": ["es2020", "dom"],
        "module": "commonjs",
        "target": "es5",
        "baseUrl": "src/ts",
        "types": ["node", "react"],
        "jsx": "react-jsx",
        "outDir": "src/js",
        "sourceMap": true,
        "strict": true,
        "allowJs": true,
        "esModuleInterop": true,
        "skipLibCheck": true,
        "noUnusedParameters": true,
        "allowUnreachableCode": false,
        "preserveConstEnums": false,
        "resolveJsonModule": true
    },
    "include": ["src/ts/**/*"]
}

I get the following error in chrome console saying im breaking the rules of hooks.

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?52c0:1476)
    at Object.useEffect (react.development.js?52c0:1519)
    at Checkbox (Checkbox.tsx?7b6e:4)
    at renderWithHooks (react-dom.development.js?61bb:14985)
    at mountIndeterminateComponent (react-dom.development.js?61bb:17811)
    at beginWork (react-dom.development.js?61bb:19049)
    at HTMLUnknownElement.callCallback (react-dom.development.js?61bb:3945)
    at Object.invokeGuardedCallbackDev (react-dom.development.js?61bb:3994)
    at invokeGuardedCallback (react-dom.development.js?61bb:4056)
    at beginWork$1 (react-dom.development.js?61bb:23964)

I've been googling for a few days now and still am clueless as to why this is happening...


Solution

  • I would really like to think that the name of the first jsx_runtime would be jsx_runtime_0 and maybe even that if there was only one jsx_runtime then it wasn't suffixed at all by a bundler!

    That's no proof, but it made me speculate whether you've actually got two versions of React coming in because each of two modules you include in your project declare it as a dependency (not a peer dependency) and therefore have their own copies which they reference in the bundle.

    Since each copy of React uses a different closure to store top-level stuff, this means it notices if e.g. useState is called in the context of a different copy of React.