TypeError: (0, _react.useEffect) n'est pas une fonction

9

dans l'environnement de développement, mon application fonctionne très bien. Dans l'environnement de production, il se bloque avec l'erreur:

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

Cela se produit dans un fichier que j'ai créé où j'importe React et useEffect comme ceci:

import React, { useEffect } from 'react'

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

  ...
}

l'ajout d'un console.log juste en dessous de cette ligne confirme que useEffect est en effet indéfini en production et la fonction attendue en développement.

J'ai vérifié mes packages.json, yarn.lock et node_modules pour toute version de react ou react-dom qui pourrait être inférieure à 16.8.0 où useEffect a été introduit. Mais tout est 16.13.1 et ils sont la principale dépendance et j'ai essayé de nettoyer mon cache de fils, de supprimer node_modules & yarn.lock et de réinstaller.

J'ai essayé de l'ajouter et de le supprimer peerDependenciessans succès.

Je mets un chèque pour m'assurer qu'il n'y a pas 2 versions distinctes de React en cours d'exécution, mais l'enregistrement window.React1 = Reactà l'intérieur de la bibliothèque et à l' window.React2 = Reactintérieur de mon application et la vérification

window.React1 === window.React2 c'était vrai, donc ce n'est pas ça non plus.

Enfin, j'ai également essayé d'alias React à celui spécifique dans node_modules, mais sans aucune chance.

La seule solution que j'ai trouvée qui fonctionne est si je l'importe comme ceci:

import React from 'react';

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

Mais cela devrait être exactement la même chose que d'utiliser une importation déstructurée? Si j'utilise explicitement React.useEffect, cela m'oblige également à changer tous mes autres crochets useState et useEffect en React.useSateetReact.useEffect

L'erreur suivante devient simplement: TypeError: (0 , _react.useState) is not a functiondans un autre fichier où j'utilise des crochets React.

Je veux résoudre le problème sans implémenter une solution de contournement.

J'utilise microbundlepour regrouper ma bibliothèque à l'aide de React. J'utilise parcel-bundlerpour importer le composant React et le rendre dans un environnement de développement (directement depuis src) ou prod (la bibliothèque fournie)

La version groupée que j'utilise est livrée avec .mjs

J'ai également vérifié la sortie du bundle .mjs minifié et à l'intérieur de React est importé comme ceci:

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

Ce qui me va bien.

Ce que je ne comprends vraiment pas, c'est comment une importation restructurée le briserait, mais simplement faire React.useEffect fonctionnerait très bien?

Voici mon package.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": "**"
  }
}

A noter également, c'est seulement React avec lequel j'ai ce problème. Toutes mes autres importations restructurées fonctionnent très bien.

MLyck
la source
L'utilisation d'importations nommées ne revient en aucun cas à référencer les membres de l'exportation par défaut. Je suppose que, au moment du développement, vous avez un chargeur supplémentaire en place qui fait des manigances pour contourner les problèmes de compatibilité hérités entre les chargeurs de modules
Aluan Haddad
1
pouvez-vous essayer l' globalindicateur --globals react=Reactet ajouter React en tant que dépendances entre pairs <- Bien que ce ne soit pas une solution appropriée. Regardez ce problème: github.com/developit/microbundle/issues/537 il semble provenir deyarn
Jee Mok
1
Pourriez-vous également essayer d'installer microbundle @ next pour voir si celui-ci a fonctionné? juste pour vérifier si c'est bien le problème de la version actuelle du microbundle
Jee Mok
Si vous utilisez TypeScript, vous pouvez également examiner ce problème: github.com/developit/microbundle/issues/564
Jee Mok
1
Je suppose que cela est arrivé à cause de l'utilisation microbundlerau lieu de react-scriptspour la génération de production, ou quelque chose de mauvais dans les configurations de bundler. Je veux attirer votre attention sur les noms des hooks react qui doivent commencer par useet qui peuvent se trouver dans cette ligne import ue,{useEffect as pe,useState as fe}from"react";qui utilise Importer les effets car pequelque chose s'est mal passé avec react. Alors, aviez-vous essayé de construire avec create-react-appet react-scripts?
Makan

Réponses:

4

Il semble que microbundlercela ne tolère pas de réagir. Celui-ci crée un bundle qui tente d'utiliser à reactpartir de la portée globale, au lieu de Reactcela vraiment exposé.

Pour la même raison, votre solution de contournement React.useEffectfonctionne comme prévu, imaginez simplement à quoi cela ressemble window.React.useEffect.

Voici un exemple d'application primitive:

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

Après le regroupement avec juste microbundlecomplètement cassé, mais lorsque vous essayez de regrouper avec

microbundle --globals react=React

comme le suggère correctement @Jee Mok, il produira un ensemble correct. J'espère que les commentaires expliqueront ce qui s'est passé.

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

Et, soit dit en passant, "importation restructurée" pas du tout à blâmer.

Kyr
la source