Webpack外部React导致React Hooks错误

时间:2020-06-04 02:25:18

标签: javascript node.js reactjs react-native

我是FireJS的作者。我遇到了带有React钩子的issue

(node:21793) UnhandledPromiseRejectionWarning: 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/warnings/invalid-hook-call-warning.html for tips about how to debug and fix this problem.
    at resolveDispatcher (webpack://%5Bname%5D/./node_modules/react/cjs/react.development.js?:1465:13)
    at useState (webpack://%5Bname%5D/./node_modules/react/cjs/react.development.js?:1496:20)
    at Header (webpack://__FIREJS_APP__/./src/pages/404.js?:22:73)
    at processChild (/media/dedsec/Data/Projects/FireJS/node_modules/react-dom/cjs/react-dom-server.node.development.js:3043:14)
    at resolve (/media/dedsec/Data/Projects/FireJS/node_modules/react-dom/cjs/react-dom-server.node.development.js:2960:5)
    at ReactDOMServerRenderer.render (/media/dedsec/Data/Projects/FireJS/node_modules/react-dom/cjs/react-dom-server.node.development.js:3435:22)
    at ReactDOMServerRenderer.read (/media/dedsec/Data/Projects/FireJS/node_modules/react-dom/cjs/react-dom-server.node.development.js:3373:29)
    at Object.renderToString (/media/dedsec/Data/Projects/FireJS/node_modules/react-dom/cjs/react-dom-server.node.development.js:3988:27)
    at /media/dedsec/Data/Projects/FireJS/dist/architects/StaticArchitect.js:51:36
    at default_1.render (/media/dedsec/Data/Projects/FireJS/dist/architects/StaticArchitect.js:57:11)
    at /media/dedsec/Data/Projects/FireJS/dist/FireJS.js:99:143
    at default_1.<anonymous> (/media/dedsec/Data/Projects/FireJS/dist/classes/Plugin.js:20:13)
    at Generator.next (<anonymous>)
    at /media/dedsec/Data/Projects/FireJS/dist/classes/Plugin.js:8:71
    at new Promise (<anonymous>)
    at __awaiter (/media/dedsec/Data/Projects/FireJS/dist/classes/Plugin.js:4:12)
(Use `node --trace-warnings ...` to show where the warning was created)
(node:21793) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 2)
(node:21793) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

我已经对help page中的每个建议进行了仔细检查,但是我无法解决该问题。

我将react捆绑为一个外部块,然后将其用作库。这是我的webpack config;

的快照
            target: 'web',
            mode: this.$.config.pro ? "production" : "development",
            entry: {
                "React": "react",
                "ReactDOM": "react-dom",
                "ReactHelmet": "react-helmet",
            },
            output: {
                path: this.$.config.paths.lib,
                filename: "e[contentHash].js",
                library: "[name]",//make file as library so it can be imported for static generation
                libraryTarget: "window"
            }
        mergedConfig.externals["react"] = 'React';
        mergedConfig.externals["react-dom"] = "ReactDOM";
        mergedConfig.externals["react-helmet"] = "ReactHelmet";
        const cssLoaderUse = [MiniCssExtractPlugin.loader,
            {
                loader: 'css-loader',
                options: {
                    modules: {
                        hashPrefix: 'hash',
                    },
                },
            }
        ];
        mergedConfig.module.rules.push({
                test: /\.(js|jsx)$/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: ["@babel/preset-env", "@babel/preset-react"]
                    }
                },
            }, {
                test: /\.sass$/i,
                loader: [...cssLoaderUse, 'sass-loader']
            }, {
                test: /\.less$/i,
                loader: [...cssLoaderUse, 'less-loader']
            }, {
                test: /\.css$/i,
                use: cssLoaderUse
            }
        );

我将其导出为window.__FIREJS_APP__

        mergedConfig.output.library = "__FIREJS_APP__";
        mergedConfig.output.libraryTarget = "window";

我要运行的react文件

import React, { useState } from 'react';

export default() => {
  // Declare a new state variable, which we'll call "count"
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

渲染过程

runApp: function (func = ReactDOM.render) {
        func(React.createElement(window.__FIREJS_APP__.default, {content: window.__MAP__.content}),
            document.getElementById("root")
        );
    }

if (window.__SSR__)
    LinkApi.runApp(ReactDOM.hydrate)
else
    LinkApi.runApp()

为什么我认为这是一个webpack问题?

以前,当我正常捆绑文件时,React Hooks可以正常工作,但是当我切换到外部React时。 React Hooks开始引起此问题。

1 个答案:

答案 0 :(得分:1)

我想出了解决此问题的方法。您需要将reactreact-domreact-dom/server捆绑到同一捆绑中。

例如:

window.React = require("react");
window.ReactDOM = require("react-dom")
window.ReactDOMServer = require("react-dom/server")

捆绑以上文件,并将其作为第一个脚本导入。