TypeError: (0, _react.useEffect) no es una función

9

cuando en el entorno de desarrollo, mi aplicación funciona bien. Cuando en el entorno de producción se bloquea con el error:

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

Sucede en un archivo que creé donde importo React y useEffect de esta manera:

import React, { useEffect } from 'react'

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

  ...
}

agregar un console.log justo debajo de esta línea confirma que useEffect está indefinido cuando está en producción y la función esperada cuando está en dev.

Revisé mi package.json, yarn.lock y node_modules para ver si hay alguna versión de react o react-dom que pueda estar por debajo de 16.8.0 donde se introdujo useEffect. Pero todo es 16.13.1 y son la dependencia principal e intenté limpiar mi caché de hilos, eliminar node_modules & yarn.lock y volver a instalar.

Intenté agregarlo y eliminarlo peerDependenciessin éxito.

Puse un cheque para asegurarme de que no hay 2 versiones separadas de React ejecutándose, pero guardando window.React1 = Reactdentro de la biblioteca y window.React2 = Reactdentro de mi aplicación y comprobando

window.React1 === window.React2 era cierto, así que tampoco es eso.

Por último, también intenté alias Reaccionar al específico en node_modules, pero sin suerte.

La única solución que he encontrado que funciona es si la importo así:

import React from 'react';

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

¿Pero esto debería ser exactamente lo mismo que usar una importación desestructurada? Si uso explícitamente React.useEffect también me obliga a cambiar todos mis otros ganchos useState y useEffect a React.useSateyReact.useEffect

El siguiente error se convierte TypeError: (0 , _react.useState) is not a functionen : en otro archivo donde uso React hooks.

Quiero resolver el problema, no implementar una solución alternativa.

Yo uso microbundlepara atar mi biblioteca utilizando reaccionar. Utilizo parcel-bundlerpara importar el componente React y renderizarlo en un entorno de desarrollo (directamente desde src) o prod (la biblioteca incluida)

La versión incluida que uso está incluida con .mjs

También verifiqué la salida del paquete .mjs minimizado y dentro de React se importa de esta manera:

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

Lo que me parece bien.

Lo que realmente no entiendo es cómo una importación reestructurada lo rompería, pero simplemente hacer React.useEffect funcionaría bien.

Aquí está mi paquete.json

{
  "name": "xxx",
  "version": "1.1.4",
  "repository": "[email protected]: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": "**"
  }
}

También vale la pena señalar, solo con React estoy teniendo este problema. Todas mis otras importaciones reestructuradas funcionan bien.

MLyck
fuente
Usar importaciones con nombre de ninguna manera es lo mismo que hacer referencia a miembros de la exportación predeterminada. Supongo que, en el momento del desarrollo, tiene un cargador adicional que está haciendo algunas travesuras para solucionar problemas de compatibilidad heredados entre los cargadores de módulos
Aluan Haddad
1
¿Puedes probar el globalindicador --globals react=Reacty agregar Reaccionar como dependencias pares <- Aunque podría no ser una solución adecuada? Mira este problema: github.com/developit/microbundle/issues/537 parece que viene deyarn
Jee Mok
1
¿Podría intentar instalar microbundle @ next para ver si funciona? solo para verificar si realmente es el problema de la versión actual de microbundle
Jee Mok
Si está utilizando TypeScript, es posible que también desee analizar este problema: github.com/developit/microbundle/issues/564
Jee Mok
1
Mi conjetura es que sucedió debido al uso en microbundlerlugar de react-scriptspara la compilación de producción, o algo alteró las configuraciones de los paquetes de una manera negativa. Quiero llamar su atención. Los nombres de los ganchos de reacción deben comenzar usey pueden estar en esta línea import ue,{useEffect as pe,useState as fe}from"react";que usan el efecto importado porque pealgo salió mal con la reacción. Entonces, ¿habías intentado construir con create-react-appy react-scripts?
Makan

Respuestas:

4

Parece que microbundlerno tolera reaccionar. Este crea un paquete que intenta usar reactdesde un alcance global, en lugar de Reacteso realmente expuesto.

Por la misma razón, su solución alternativa React.useEffectfunciona como se esperaba, solo imagine que se ve así window.React.useEffect.

Aquí hay un ejemplo de una aplicación primitiva:

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'));

Después de agrupar con solo microbundlecompletamente roto, pero cuando intentas agrupar con

microbundle --globals react=React

como sugiere correctamente @Jee Mok, producirá el paquete correcto. Espero que los comentarios expliquen lo que pasó.

!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>

Y, por cierto, la "importación reestructurada" no tiene la culpa.

Kyr
fuente