Ошибка типа: (0, _react.useEffect) не является функцией - PullRequest
9 голосов
/ 21 апреля 2020

в среде разработки мое приложение работает просто отлично. Когда в производственной среде происходит сбой с ошибкой:

Uncaught TypeError: (0 , _react.useEffect) is not a function

Это происходит в созданном мной файле, где я импортирую React и используюEffect следующим образом:

import React, { useEffect } from 'react'

const X = () => {
  useEffect(() => { ... })

  ...
}

добавление console.log чуть ниже этой строки подтверждает, что useEffect действительно не определено при работе, и ожидаемая функция при работе в dev.

Я проверил свой пакет. json, yarn.lock & node_modules для любых реакций или версия response-dom, которая может быть под 16.8.0, где был введен useEffect. Но все 16.13.1, и они являются основной зависимостью, и я попытался очистить кэш пряжи, удалить node_modules & yarn.lock и переустановить.

Я попытался добавить и удалить его из peerDependencies безуспешно.

Я поставил проверку, чтобы убедиться, что не запущены 2 отдельные версии React, но сохранил window.React1 = React внутри библиотеки и window.React2 = React внутри моего приложения и проверил

window.React1 === window.React2 это было правдой, так что это тоже не так.

Наконец, я также попытался псевдоним Реагировать на указанный c один в node_modules, но без какой-либо удачи.

Единственный Я нашел решение, которое работает, если я импортирую его так:

import React from 'react';

const X = () => {
  React.useEffect(() => { ... })
  ...
}

Но это должно быть точно так же, как при использовании деструктурированного импорта? Если я явно использую React.useEffect, это также вынуждает меня изменить все мои другие хуки useState и useEffect на React.useSate и React.useEffect

Следующая ошибка просто становится: TypeError: (0 , _react.useState) is not a function в другом файле, где я используйте перехватчики React.

Я хочу решить проблему, а не реализовывать обходной путь.

Я использую microbundle, чтобы связать свою библиотеку с помощью React. Я использую parcel-bundler для импорта компонента React и рендеринга его в среде разработчика (напрямую из sr c) или prod (в комплекте библиотеки)

Используемая в комплекте версия входит в комплект .m js

Я также проверил вывод минимизированного пакета .m js, и внутри React импортируется так:

import ue,{useEffect as pe,useState as fe}from"react";

Что выглядит нормально меня.

Что я действительно не понимаю, так это то, как реструктурированный импорт может сломать его, но просто выполнение React.useEffect будет работать нормально?

Вот мой пакет. json

{
  "name": "xxx",
  "version": "1.1.4",
  "repository": "git@github.com:xxx/xxx.git",
  "author": "xxx",
  "license": "MIT",
  "source": "src/index.ts",
  "main": "dist/bundle.js",
  "umd:main": "dist/bundle.umd.js",
  "module": "dist/bundle.mjs",
  "publishConfig": {
    "registry": "https://npm.pkg.github.com/@xxx"
  },
  "scripts": {
    "build": "microbundle",
    "dev": "parcel ./test-app/dev/index.html --port 3000",
    "start": "parcel ./test-app/serve/index.html --port 3000",
    "storybook": "start-storybook -s ./public -c .storybook --ci",
    "prepublishOnly": "yarn build"
  },
  "dependencies": {
    "@api-platform/admin": "2.1.0",
    "@api-platform/api-doc-parser": "0.8.2",
    "@fortawesome/fontawesome-svg-core": "^1.2.28",
    "@fortawesome/free-solid-svg-icons": "^5.13.0",
    "@fortawesome/react-fontawesome": "^0.1.9",
    "@material-ui/core": "^4.9.10",
    "@material-ui/icons": "^4.9.1",
    "@react-keycloak/web": "^2.1.1",
    "@types/pluralize": "^0.0.29",
    "google-geocoder": "0.2.1",
    "history": "^4.10.1",
    "keycloak-js": "^9.0.3",
    "lodash.debounce": "^4.0.8",
    "lodash.omit": "^4.5.0",
    "lodash.set": "4.3.2",
    "notistack": "0.9.9",
    "papaparse": "^5.2.0",
    "parcel-bundler": "1.12.4",
    "polished": "^3.5.2",
    "react": "16.13.1",
    "react-admin": "3.4.1",
    "react-dom": "16.13.1",
    "react-is": "16.13.1",
    "react-redux": "^7.2.0",
    "recompose": "^0.30.0",
    "redux": "4.0.5",
    "styled-components": "5.1.0"
  },
  "devDependencies": {
    "@babel/core": "7.9.0",
    "@babel/plugin-syntax-export-default-from": "7.8.3",
    "@babel/preset-env": "7.9.5",
    "@babel/preset-react": "7.9.4",
    "@storybook/addon-a11y": "5.3.18",
    "@storybook/addon-actions": "5.3.18",
    "@storybook/addon-info": "5.3.18",
    "@storybook/addon-knobs": "5.3.18",
    "@storybook/addon-links": "5.3.18",
    "@storybook/addon-storyshots": "5.3.18",
    "@storybook/addon-storysource": "5.3.18",
    "@storybook/addon-viewport": "5.3.18",
    "@storybook/react": "5.3.18",
    "@testing-library/react": "^10.0.3",
    "@types/jsonld": "1.5.1",
    "@types/lodash": "4.14.149",
    "@types/node": "13.11.1",
    "@types/papaparse": "5.0.3",
    "@types/react-redux": "7.1.7",
    "@types/recompose": "^0.30.7",
    "@types/styled-components": "5.1.0",
    "@welldone-software/why-did-you-render": "4.0.7",
    "awesome-typescript-loader": "5.2.1",
    "babel-loader": "^8.1.0",
    "babel-plugin-module-resolver": "4.0.0",
    "babel-plugin-styled-components": "1.10.7",
    "lodash.get": "4.4.2",
    "lodash.uniq": "4.5.0",
    "microbundle": "0.11.0",
    "openapi-types": "1.3.5",
    "parcel-plugin-static-files-copy": "2.3.1",
    "pluralize": "^8.0.0"
  },
  "alias": {
    "jsonld": "./node_modules/jsonld/dist/jsonld.js"
  },
  "staticFiles": {
    "staticPath": "public",
    "watcherGlob": "**"
  }
}

Также стоит отметить, что это только React, с которой у меня эта проблема. Весь мой другой реструктурированный импорт работает нормально.

1 Ответ

4 голосов
/ 29 апреля 2020

Кажется, что microbundler не терпит Реагировать. Этот пакет создания, который пытается использовать react из глобальной области видимости, вместо React, который действительно показал.

По той же причине, что ваш обходной путь с React.useEffect работает, как и ожидалось, просто представьте, что он выглядит как window.React.useEffect.

Вот пример примитивного приложения:

import ReactDOM from 'react-dom';
import React, { useEffect, useState } from 'react';

/**
 * necessary workaround, microbundle use `h` pragma by default,
 * that undefined when use React
 * another option is to make build with option --jsx
 * @example microbundle --globals react=React --jsx React.createElement
 * yes, yet another workaround
*/
window.h = React.createElement;

const X = () => {
  const [A, B] = useState('world');

  useEffect(() => {
    B('MLyck');
  }, [])

  return `Hello ${A}`;
}

ReactDOM.render(<X />, document.querySelector('react-app'));

После связывания просто с microbundle оно полностью ломается, но при попытке связать с

microbundle --globals react=React

Как правильно предположить @Jee Mok, он выдаст правильную связку. Я надеюсь, что комментарии объяснят, что случилось.

!function (e, t) {
  "object" == typeof exports && "undefined" != typeof module ?
    t(require("react-dom"), require("react")) :
    "function" == typeof define && define.amd ?
      define(["react-dom", "react"], t) :
      t(e.ReactDOM, e.React);
  /*
  String above is core of problem,
  in case you try to bundle without options `--globals react=React`
  it will looks like: `t(e.ReactDOM, e.react);`
  Obviously `react` is not defined in `e` e.g. `this` e.g. `window`
  due to react expose self as `React`
   */
}(this, function (e, t) {
  e = e && e.hasOwnProperty("default") ? e.default : e, window.h = ("default" in t ? t.default : t).createElement, e.render(h(function () {
    var e = t.useState("world"), n = e[0], r = e[1];
    return t.useEffect(function () {
      r("MLyck");
    }, []), "Hello " + n;
  }, null), document.querySelector("react-app"));
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.development.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.development.js"></script>

    <react-app></react-app>

И, кстати, «реструктурированный импорт» вовсе не виноват.

...