Getting "Cannot call a class as a function" in my React Project
Asked Answered
S

33

155

I'm trying to add a React map component to my project but run into an error. I'm using Fullstack React's blog post as a reference. I tracked down where the error gets thrown in google_map.js line 83:

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

Here is my map component so far. The page loads just fine (without a map) when I comment out lines 58-60, the last three lines. edit: I made the changes that @Dmitriy Nevzorov suggested and it still gives me the same error.

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)

And here is where this map component gets routed in 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'))
Selle answered 20/7, 2016 at 12:52 Comment(7)
You have two export defaults, and would it be new GoogleAPIComponent() not GoogleAPIComponent()?Insensible
I removed one of the defaults and tried your suggestion. It looks like it is actually talking to Google Maps now, which is good, but before the page can load it throws another cryptic error: Locations.js:58 Uncaught TypeError: (intermediate value) is not a function". Any ideas?Selle
What if you remove the (LocationContainer)?Insensible
Thanks, I think that got it! Weird, that's how they have it written on their blog post. Still getting a few other errors from Google Maps, I'll put them here: 'GoogleMap: apiKey is deprecated, use bootstrapURLKeys={{key: YOUR_API_KEY}} instead. google_map.js:689 GoogleMap: center or defaultCenterproperty must be defined google_map.js:699 GoogleMap: zoom or defaultZoomproperty must be defined google_map.js: 704'Selle
I'm not sure about the other errors, but you could try this to fix the first one: export default new GoogleApiComponent({ bootstrapURLKeys: MY_API_KEY })Insensible
Thanks, that took care of that. I ran into more issues with this repo not being able to mesh well with the existing project and the API so I scrapped it and used React-Gmap instead. I spent about a day using this repo and within an hour I had the other up and running. Thanks again for all your help!Selle
Check that you're missing new when trying to initiate a classMeg
T
228

For me it happened when I forgot to write extends React.Component at the end. I know it's not exactly what YOU had, but others reading this answer can benefit from this, hopefully.

Talbot answered 8/3, 2017 at 19:42 Comment(3)
There's great post at overreacted that explains why this works overreacted.io/how-does-react-tell-a-class-from-a-functionGrantee
Summary of post: Distinguishing between a class and a function in browser is actually not completely trivial ... "The actual solution is really simple, but [I'm going on a] huge tangent to explain why React ended up with this solution ..." blah, blah, blah, ... -> "If you don’t extend React.Component, React won’t find isReactComponent on the prototype, and won’t treat component as a class."Leonilaleonine
Great. I was facing the similar issue & your solution fixed the issue. But my syntax was import React, { Component } from 'react'; class extends Component. I couldn't understand how did this resolve the issue by replacing Component with React.Component. Does the import matters?Dated
E
116

For me it was because I forgot to use the new keyword when setting up Animated state.

eg:

fadeAnim: Animated.Value(0),

to

fadeAnim: new Animated.Value(0),

would fix it.


Edit from 5 years on with more explanation:

The most likely issue is that you're missing the new keyword somewhere, just like I did above. What this means is you don't even need to be using React to come across this error.

The issue is that in JS you can create classes like so (Example from MDN):

class Rectangle {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }

  calcArea() {
    return this.height * this.width;
  }

}

If you wanted to use this class, you need to create a new instance of it like so:

const rect = new Rect(height, width);

The reason for this problem is often you're trying to do a function call to the definition of the class (or something inside the definition), rather than an instance of the class.

Essentially, in code, you're doing this:

Rectangle.calcArea() // incorrect!

when you should be doing

rect.calcArea() // correct!
Ebon answered 20/11, 2017 at 11:26 Comment(7)
This solved my problem, I was using a different use case not the animated but after using the new keyword solved it. Thank youAlesandrini
Spent 4 hours 44 minutes and 4 seconds trying to know wth happened. You are god.Nembutal
Yup, that was me too. Thank you!Archetype
Does someone know in which version it changed? (another thing to worry about RN)Th
The same exact thing happened to me, and I mean Exact (down to the variable name). Creepy...Requisition
After crawling all over the place in a vain attempt to resolve my problem, this simple fix was wot dun it for me (Brits will understand that)! Thank you so much! I was going spare! Incidentally, my issue was with a plan vanilla script. I don't use React so your solution may work in other contexts too.Subgenus
@ThomasMurphy Glad to help! You're absolutely right. It has been 5 years since I answered this question, and I understand the issue more now. The most common cause for this issue will be that you've missed new keyword somewhere. By using the new keyword, you're creating an instance of a class, rather than referencing the class itself.Ebon
I
66

tl;dr

If you use React Router v4 check your <Route/> component if you indeed use the component prop to pass your class based React component!

More generally: If your class seems ok, check if the code that calls it doesn't try to use it as a function.

Explanation

I got this error because I was using React Router v4 and I accidentally used the render prop instead of the component one in the <Route/> component to pass my component that was a class. This was a problem, because render expects (calls) a function, while component is the one that will work on React components.

So in this code:

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

The line containing the <Route/> component, should have been written like this:

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

It is a shame, that they don't check it and give a usable error for such and easy to catch mistake.

Intrinsic answered 25/6, 2017 at 20:55 Comment(0)
R
52

Happened to me because I used

PropTypes.arrayOf(SomeClass)

instead of

PropTypes.arrayOf(PropTypes.instanceOf(SomeClass))

Redbird answered 23/6, 2017 at 12:16 Comment(3)
Thanks, wrong PropTypes definition was the issue in my case.Audun
this solved my issue! was PropTypes.oneOfType([SomeClass, SomeOtherClass]).isRequired, instead of PropTypes.oneOfType([PropTypes.instanceOf(SomeClass), PropTypes.instanceOf(SomeOtherClass)]).isRequired,Admission
Thanks, was really wondering for a long time what was going wrong there!Logging
A
17

For me, it was ComponentName.prototype instead of ComponentName.propTypes. auto suggested by Phpstorm IDE. Hope it will help someone.

Ahithophel answered 18/1, 2018 at 2:3 Comment(1)
yeah this happen to mePrimal
V
16

I experienced the same issue, it occurred because my ES6 component class was not extending React.Component.

Viceroy answered 15/6, 2017 at 14:52 Comment(0)
T
15

You have duplicated export default declaration. The first one get overridden by second one which is actually a function.

Trooper answered 20/7, 2016 at 13:16 Comment(1)
Good catch! I left the default in front of GoogleApiComponent and I still get the same error. Alternatively, removing all defaults gives me an "unexpected token" error in my terminal on GoogleApiComponent.Selle
B
8

Mostly these issues occur when you miss extending Component from react:

import React, {Component} from 'react'

export default class TimePicker extends Component {
    render() {
        return();     
    }
}
Buccal answered 22/11, 2017 at 7:11 Comment(0)
U
7

For me it was because i used prototype instead of propTypes

class MyComponent extends Component {

 render() {
    return <div>Test</div>;
  }
}

MyComponent.prototype = {

};

it ought to be

MyComponent.propTypes = {

};
Uncover answered 14/9, 2018 at 1:10 Comment(1)
Exact same case for me. Thank you!Humanly
V
6
Post.proptypes = {

}

to

Post.propTypes = {

}

someone should comment on how to monitor such error in a very precise way.

Vouchsafe answered 31/10, 2018 at 6:14 Comment(2)
It is better to explain your solution/answer with some detailed information.Zosema
Yaah it happens, Bravo !Vouchsafe
S
6

Two things you can check is,

class Slider extends React.Component {
    // Your React Code
}

Slider.propTypes = {
    // accessibility: PropTypes.bool,
}
  • Make sure that you extends React.Component
  • Use propTypes instead of prototype (as per IDE intellisense)
Sotelo answered 2/10, 2019 at 13:31 Comment(1)
should be Slider.propTypes: { }Fulfill
G
5

This is a general issue, and doesn't appear in a single case. But, the common problem in all the cases is that you forget to import a specific component (doesn't matter if it's either from a library that you installed or a custom made component that you created):

import {SomeClass} from 'some-library'

When you use it later, without importing it, the compiler thinks it's a function. Therefore, it breaks. This is a common example:

imports

...code...

and then somewhere inside your code

<Image {..some props} />

If you forgot to import the component <Image /> then the compiler will not complain like it does for other imports, but will break when it reaches your code.

Girand answered 16/2, 2019 at 16:8 Comment(0)
A
4

Looks like there're no single case when this error appears.

Happened to me when I didn't declare constructor in statefull component.

class MyComponent extends Component {

    render() {
        return <div>Test</div>;
    }
}

instead of

class MyComponent extends Component {

    constructor(props) {
        super(props);
    }

    render() {
        return <div>Test</div>;
    }
}
Alcaeus answered 27/9, 2017 at 19:21 Comment(0)
D
2

In file MyComponent.js

export default class MyComponent extends React.Component {
...
}

I put some function related to that component:

export default class MyComponent extends React.Component {
...
}

export myFunction() {
...
}

and then in another file imported that function:

import myFunction from './MyComponent'
...
myFunction() // => bang! "Cannot call a class as a function"
...

Can you spot the problem?

I forgot the curly braces, and imported MyComponent under name myFunction!

So, the fix was:

import {myFunction} from './MyComponent'
Duplet answered 18/8, 2018 at 9:1 Comment(0)
C
2

I received this error by making small mistake. My error was exporting the class as a function instead of as a class. At the bottom of my class file I had:

export default InputField();

when it should have been:

export default InputField;
Chevalier answered 17/9, 2019 at 19:43 Comment(0)
O
1

For me, it was because I'd accidentally deleted my render method !

I had a class with a componentWillReceiveProps method I didn't need anymore, immediately preceding a short render method. In my haste removing it, I accidentally removed the entire render method as well.

This was a PAIN to track down, as I was getting console errors pointing at comments in completely irrelevant files as being the "source" of the problem.

Orose answered 15/9, 2017 at 3:12 Comment(0)
B
1

I had a similar problem I was calling the render method incorrectly

Gave an error:

render = () => {
    ...
}

instead of

correct:

render(){
    ...
}
Brunel answered 24/10, 2017 at 5:39 Comment(0)
F
1

I had it when I did so :

function foo() (...) export default foo

correctly:

export default  () =>(...);

or

const foo = ...
export default foo
Firedamp answered 23/2, 2018 at 15:40 Comment(0)
T
1

For me it happened because I didn't wrap my connect function properly, and tried to export default two components

Taxidermy answered 4/6, 2018 at 1:36 Comment(0)
T
1

I faced this error when I imported the wrong class and referred to wrong store while using mobx in react-native.

I faced error in this snippet :

import { inject, Observer } from "mobx-react";

@inject ("counter")
@Observer

After few corrections like as below snippet. I resolved my issue like this way.

import { inject, observer } from "mobx-react";

@inject("counterStore")
@observer

What was actually wrong,I was using the wrong class instead of observer I used Observer and instead of counterStore I used counter. I solved my issue like this way.

Timberland answered 7/8, 2018 at 9:25 Comment(0)
S
1

I experienced this when writing an import statement wrong while importing a function, rather than a class. If removeMaterial is a function in another module:

Right:

import { removeMaterial } from './ClaimForm';

Wrong:

import removeMaterial from './ClaimForm';
Saraann answered 25/8, 2018 at 0:37 Comment(0)
U
0

I have also run into this, it is possible you have a javascript error inside of your react component. Make sure if you are using a dependency you are using the new operator on the class to instantiate the new instance. Error will throw if

this.classInstance = Class({})

instead use

this.classInstance = new Class({})

you will see in the error chain in the browser

at ReactCompositeComponentWrapper._constructComponentWithoutOwner

that is the giveaway I believe.

Unstuck answered 4/10, 2017 at 1:3 Comment(0)
R
0

In my case i wrote comment in place of Component by mistake

I just wrote this.

import React, { Component } from 'react';

  class Something extends Component{
      render() {
          return();
     }
  }

Instead of this.

import React, { Component } from 'react';

  class Something extends comment{
      render() {
          return();
     }
  }

it's not a big deal but for a beginner like me it's really confusing. I hope this will be helpfull.

Retouch answered 10/8, 2018 at 16:24 Comment(0)
D
0

In my case, using JSX a parent component was calling other components without the "<>"

 <ComponentA someProp={someCheck ? ComponentX : ComponentY} />

fix

<ComponentA someProp={someCheck ? <ComponentX /> : <ComponentY />} />
Demagogy answered 27/8, 2018 at 20:11 Comment(0)
S
0

Another report here: It didn't work as I exported:

export default compose(
  injectIntl,
  connect(mapStateToProps)(Onboarding)
);

instead of

export default compose(
  injectIntl,
  connect(mapStateToProps)
)(Onboarding);

Note the position of the brackets. Both are correct and won't get caught by either a linter or prettier or something similar. Took me a while to track it down.

Sizeable answered 29/10, 2018 at 15:55 Comment(0)
S
0

In my case, I accidentally put component name (Home) as the first argument to connect function while it was supposed to be at the end. duh.

This one -surely- gave me the error:

export default connect(Home)(mapStateToProps, mapDispatchToProps)

But this one worked -surely- fine:

export default connect(mapStateToProps, mapDispatchToProps)(Home)
Stetson answered 30/10, 2018 at 10:9 Comment(0)
T
0

This occured when I accidentally named my render function incorrectly:

import React from 'react';

export class MyComponent extends React.Component {
  noCalledRender() {
    return (
      <div>
        Hello, world!
      </div>
    );
  }
}

My instance of this error was simply caused because my class did not have a proper render method.

Toe answered 2/1, 2019 at 19:33 Comment(0)
P
0

Actually all the problem redux connect. solutions:

Correct:

export default connect(mapStateToProps, mapDispatchToProps)(PageName)

Wrong & Bug:

export default connect(PageName)(mapStateToProps, mapDispatchToProps)
Pasquinade answered 27/5, 2019 at 12:55 Comment(0)
D
0

In my scenario I was attempting to use hot reloading on a custom hook (not sure why, probably just muscle memory when creating components).

const useCustomHook = () => {
    const params = useParams();
    return useSelector(
        // Do things
    );
};

// The next line is what breaks it
export default hot(module)(useCustomHook);

The correct way

const useCustomHook = () => {
    const params = useParams();
    return useSelector(
        // Do things
    );
};

export default useCustomHook;

Apparently you can't hot reload hook 😅 😂

Delft answered 25/6, 2021 at 21:2 Comment(0)
C
0

In my case I accidentally called objectOf

static propTypes = {
    appStore: PropTypes.objectOf(AppStore).isRequired
}

Instead of instanceOf:

static propTypes = {
    appStore: PropTypes.instanceOf(AppStore).isRequired
}
Costanzo answered 27/5, 2022 at 20:44 Comment(0)
D
0

Well, I found a solution to my problem with this same error.

I made a very silly mistake by using the class Alert('hi') directly instead of the function alert('hi').

Fortunately, I found this within an hour. So a lot of time was saved.

Lookout for those class instance use cases where you were supposed to use the functions. This doesn't necessarily need to be in the same class as the one you were modifying. Even if it's present in just one file out of all the files, it will throw the same error.

One way you can find it is by navigating between screens, the error will be thrown when you are on the screen where error exists.

Dingy answered 26/1 at 18:10 Comment(0)
T
-1

For me it was a wrong import of a reducer in the rootReducer.js. I imported container instead of reducer file.

Example

import settings from './pages/Settings';

But sure it should be

import settings from './pages/Settings/reducer';

Where settings directory contains following files actions.js, index.js, reducer.js.

To check it you can log reducers arg of the assertReducerShape() function from the redux/es/redux.js.

Tea answered 9/8, 2018 at 18:47 Comment(0)
P
-2

If you're on Node JS and you're seeing this error in a Class you've added to support a Cucumber test, it's because Cucumber will automatically try to run anything that exports a function, and NodeJS internally converts a Class to a function.

So instead of this:

module.exports = MyClass;

do this:

module.exports.MyClass = MyClass;

Then, when you import it into your steps file, do it like this:

let MyClass = require("myclass.js").MyClass;

This way you're not exporting a function. Read more here.

Peppermint answered 31/12, 2017 at 17:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.