TypeError: (0, _react.useEffect) non è una funzione


9

quando in ambiente di sviluppo, la mia app funziona perfettamente. Quando nell'ambiente di produzione si blocca con l'errore:

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

Succede in un file che ho creato dove importare React e useEffect in questo modo:

import React, { useEffect } from 'react'

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

  ...
}

l'aggiunta di un console.log proprio sotto questa riga conferma che useEffect è effettivamente indefinito quando in produzione e la funzione prevista in dev.

Ho controllato il mio package.json, yarn.lock e node_modules per qualsiasi versione di reazione o di reazione che potesse essere inferiore a 16.8.0 in cui è stato introdotto useEffect. Ma tutto è 16.13.1 e sono la dipendenza principale e ho provato a pulire la cache del mio filato, eliminare node_modules & yarn.lock e reinstallare.

Ho provato ad aggiungerlo e rimuoverlo peerDependenciessenza successo.

Ho messo un segno di spunta per assicurarmi che non ci siano 2 versioni separate di React in esecuzione, ma il salvataggio window.React1 = Reactall'interno della libreria e window.React2 = Reactall'interno della mia applicazione e il controllo

window.React1 === window.React2 era vero, quindi neanche quello.

Infine, ho anche provato ad alias React a quello specifico in node_modules, ma senza fortuna.

L'unica soluzione che ho trovato che funziona è se lo importa in questo modo:

import React from 'react';

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

Ma questo dovrebbe essere esattamente lo stesso che usare un'importazione destrutturata? Se uso esplicitamente React.useEffect, mi costringe anche a cambiare tutti gli altri miei usi useState e useEffect in React.useSateeReact.useEffect

L'errore successivo diventa: TypeError: (0 , _react.useState) is not a functionin un altro file in cui utilizzo gli hook di React.

Voglio risolvere il problema non implementare una soluzione alternativa.

Uso microbundleper raggruppare la mia libreria usando React. Uso parcel-bundlerper importare il componente React e renderlo in un ambiente di sviluppo (direttamente da SRC) o prod (la libreria in bundle)

La versione in bundle che uso è in bundle con .mjs

Ho controllato anche l'output del bundle .mjs minimizzato e all'interno di React viene importato in questo modo:

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

Il che mi sembra perfetto.

Quello che davvero non capisco è come un'importazione ristrutturata la spezzerebbe, ma solo facendo React.useEffect funzionerebbe bene?

Ecco il mio package.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": "**"
  }
}

Vale anche la pena notare che è solo React con questo problema. Tutte le altre mie importazioni ristrutturate funzionano bene.


L'utilizzo delle importazioni con nome non equivale a fare riferimento ai membri dell'esportazione predefinita. La mia ipotesi è che, al momento dello sviluppo, ci sia un caricatore aggiuntivo in atto che sta facendo alcuni shenanigans per aggirare i problemi di compatibilità legacy tra i caricatori di moduli
Aluan Haddad,

1
puoi provare il globalflag --globals react=Reacte aggiungere React come dipendenze tra pari <- Anche se potrebbe non essere una soluzione corretta. Guarda questo numero: github.com/developit/microbundle/issues/537 sembra provenire dayarn
Jee Mok

1
Potresti anche provare a installare microbundle @ next per vedere se quello ha funzionato? solo per verificare se si tratta effettivamente dell'attuale versione della microbundle
Jee Mok il

Se stai usando TypeScript, potresti anche voler esaminare questo problema: github.com/developit/microbundle/issues/564
Jee Mok

1
La mia ipotesi è che sia successo a causa dell'utilizzo microbundlerinvece che react-scriptsper la build di produzione, o qualcosa che ha alterato le configurazioni del bundler in modo negativo. Voglio attirare la tua attenzione. I nomi degli hook di reazione dovrebbero iniziare con usee potrebbero essere in questa riga import ue,{useEffect as pe,useState as fe}from"react";che usano Effetti importati quando pequalcosa è andato storto con reagire. Quindi, hai provato a costruire con create-react-appe react-scripts?
Makan,

Risposte:


4

Sembra che microbundlernon tolleri di reagire. Questo crea un bundle che tenta di utilizzare reactdall'ambito globale, invece Reactche è realmente esposto.

Per lo stesso motivo la tua soluzione alternativa React.useEffectfunziona come previsto, immagina che assomigli window.React.useEffect.

Ecco un esempio di un'applicazione 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'));

Dopo aver raggruppato con solo microbundlecompletamente rotto, ma quando si tenta di raggruppare

microbundle --globals react=React

come suggerisce correttamente @Jee Mok, produrrà il pacchetto corretto. Spero che i commenti spieghino cosa è successo.

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

E, a proposito, "importazione ristrutturata" non è affatto colpa.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.