155 votes

J'obtiens "Cannot call a class as a function" dans mon projet React.

J'essaie d'ajouter un composant React map à mon projet mais je me heurte à une erreur. J'utilise le composant React de Fullstack. article de blog comme référence. J'ai trouvé l'origine de l'erreur dans google_map.js ligne 83 :

function _classCallCheck(instance, Constructor) { 
  if (!(instance instanceof Constructor)) { 
    throw new TypeError("Cannot call a class as a function"); 
    } 
  }

Voici le composant de ma carte jusqu'à présent. La page se charge très bien (sans carte) lorsque je commente les lignes 58-60, les trois dernières lignes. edit : J'ai fait les changements suggérés par @Dmitriy Nevzorov et cela me donne toujours la même erreur.

import React from 'react'
import GoogleApiComponent from 'google-map-react'

export class LocationsContainer extends React.Component {
    constructor() {
        super()
    }
  render() {
    const style = {
        width: '100vw',
        height: '100vh'
    }
    return (
      <div style={style}>
        <Map google={this.props.google} />
      </div>
    )
  }
}

export class Map extends React.Component {
    componentDidUpdate(prevProps, prevState){
        if (prevProps.google !== this.props.google){
            this.loadMap();
        }
    }
    componentDidMount(){
        this.loadMap();
    }
    loadMap(){
        if (this.props && this.props.google){
            const {google} = this.props;
            const maps = google.maps;

            const mapRef = this.refs.map;
            const node = ReactDOM.findDOMNode(mapRef);

            let zoom = 14;
            let lat = 37.774929
            let lng = 122.419416
            const center = new maps.LatLng(lat, lng);
            const mapConfig = Object.assign({}, {
                center: center,
                zoom: zoom
            })
            this.map = new maps.Map(node, mapConfig)
        }
    }
    render() {
        return (
            <div ref='map'>
                Loading map...
            </div>
        )
    }
}

export default GoogleApiComponent({
  apiKey: MY_API_KEY
})(LocationsContainer)

Et voici où ce composant de carte est acheminé dans main.js :

import {render} from 'react-dom';
import React from 'react';
import Artists from './components/Artists'
import { Router, Route, Link, browserHistory } from 'react-router'
import Home from './components/HomePage'
import Gallery from './components/ArtGallery'
import ArtistPage from './components/ArtistPage'
import FavsPage from './components/FavsPage'
import LocationsContainer from './components/Locations'

//Create the route configuration
render((
  <Router history={browserHistory}>
    <Route path="/" component={Home} />
        <Route path="locations" component={LocationsContainer} />
        <Route path="artists" component={Artists} /> 
        <Route path="gallery" component={Gallery} />     
      <Route path="favorites" component={FavsPage} />
      <Route path=":artistName" component={ArtistPage} />
  </Router>
), document.getElementById('app'))

3 votes

Vous avez deux export default et serait-il new GoogleAPIComponent() pas GoogleAPIComponent() ?

0 votes

J'ai supprimé une des valeurs par défaut et j'ai essayé votre suggestion. Il semble qu'il communique maintenant avec Google Maps, ce qui est une bonne chose, mais avant que la page ne puisse se charger, une autre erreur énigmatique se produit : Locations.js:58 Uncaught TypeError : (valeur intermédiaire) n'est pas une fonction". Une idée ?

1 votes

Et si vous retirez le (LocationContainer) ?

223voto

programmer Points 426

Pour moi, c'est arrivé quand j'ai oublié d'écrire extends React.Component à la fin. Je sais que ce n'est pas exactement ce que VOUS avez eu, mais d'autres personnes lisant cette réponse peuvent en bénéficier, je l'espère.

21 votes

Il y a un excellent article chez overreacted qui explique pourquoi cela fonctionne. overreacted.io/how-does-react-tell-a-class-from-a-function

3 votes

Résumé du poste : Distinguer entre une classe et une fonction dans le navigateur n'est en fait pas complètement trivial .... "La solution réelle est vraiment simple, mais [je vais prendre] une énorme tangente pour expliquer pourquoi React a abouti à cette solution ..." bla, bla, bla, ... -> "Si vous n'étendez pas React.Component, React ne trouvera pas isReactComponent sur le prototype, et ne traitera pas component comme une classe."

0 votes

Super. J'étais confronté à un problème similaire et votre solution a réglé le problème. Mais ma syntaxe était import React, { Component } from 'react'; class extends Component . Je n'ai pas compris comment cela a permis de résoudre le problème en remplaçant Component con React.Component . L'importation est-elle importante ?

112voto

William Park Points 512

Pour moi, c'est parce que j'ai oublié d'utiliser la fonction new lors de la mise en place de l'état animé.

eg :

fadeAnim: Animated.Value(0),

à

fadeAnim: new Animated.Value(0),

le réparerait.

2 votes

Cela a résolu mon problème, j'utilisais un cas d'utilisation différent, pas l'animé, mais après avoir utilisé le nouveau mot-clé, je l'ai résolu. Merci pour votre aide.

10 votes

J'ai passé 4 heures 44 minutes et 4 secondes à essayer de savoir ce qui s'est passé. Vous êtes Dieu.

0 votes

Ouaip, c'était moi aussi. Merci !

65voto

totymedli Points 4228

Tl;dr

Si vous utilisez React Router v4 vérifiez votre <Route/> si vous utilisez effectivement le composant component prop pour passer votre composant React basé sur une classe !

Plus généralement : Si votre classe semble correcte, vérifiez si le code qui l'appelle n'essaie pas de l'utiliser comme une fonction.

Explication

J'ai obtenu cette erreur parce que j'utilisais React Router v4 et que j'ai accidentellement utilisé l'attribut render au lieu de la component un dans le <Route/> pour passer mon composant qui était une classe. C'était un problème, car render attend (appelle) une fonction, tandis que component est celui qui fonctionnera sur les composants React.

Donc dans ce code :

<HashRouter>
    <Switch>
        <Route path="/" render={MyComponent} />
    </Switch>
</HashRouter>

La ligne contenant le <Route/> composant, aurait dû être écrit comme ça :

<Route path="/" component={MyComponent} />

C'est une honte, qu'ils ne le vérifient pas et ne donnent pas une erreur utilisable pour une erreur aussi facile à attraper.

52voto

Dan Balaban Points 479

Ça m'est arrivé parce que j'ai utilisé

PropTypes.arrayOf(SomeClass)

au lieu de

PropTypes.arrayOf(PropTypes.instanceOf(SomeClass))

0 votes

Merci, la mauvaise définition de PropTypes était le problème dans mon cas.

0 votes

Cela a résolu mon problème ! PropTypes.oneOfType([SomeClass, SomeOtherClass]).isRequired, au lieu de PropTypes.oneOfType([PropTypes.instanceOf(SomeClass), PropTypes.instanceOf(SomeOtherClass)]).isRequired,

0 votes

Merci, je me suis longtemps demandé ce qui n'allait pas là !

15voto

Dmitriy Nevzorov Points 4347

Vous avez dupliqué export default déclaration. La première est remplacée par la seconde qui est en fait une fonction.

0 votes

Bien vu ! J'ai laissé la valeur par défaut devant GoogleApiComponent et j'obtiens toujours la même erreur. Alternativement, la suppression de tous les défauts me donne une erreur "unexpected token" dans mon terminal sur GoogleApiComponent.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X