Getting "Cannot call a class as a function" in my React Project - javascript

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

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.

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!

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.

Happened to me because I used
PropTypes.arrayOf(SomeClass)
instead of
PropTypes.arrayOf(PropTypes.instanceOf(SomeClass))

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

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

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

Mostly these issues occur when you miss extending Component from react:
import React, {Component} from 'react'
export default class TimePicker extends Component {
render() {
return();
}
}

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 = {
};

Post.proptypes = {
}
to
Post.propTypes = {
}
someone should comment on how to monitor such error in a very precise way.

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)

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>;
}
}

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.

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'

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;

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.

I had a similar problem I was calling the render method incorrectly
Gave an error:
render = () => {
...
}
instead of
correct:
render(){
...
}

I had it when I did so :
function foo() (...) export default foo
correctly:
export default () =>(...);
or
const foo = ...
export default foo

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

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.

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

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.

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.

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 />} />

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.

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)

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.

Actually all the problem redux connect. solutions:
Correct:
export default connect(mapStateToProps, mapDispatchToProps)(PageName)
Wrong & Bug:
export default connect(PageName)(mapStateToProps, mapDispatchToProps)

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 😅 😂

In my case I accidentally called objectOf
static propTypes = {
appStore: PropTypes.objectOf(AppStore).isRequired
}
Instead of instanceOf:
static propTypes = {
appStore: PropTypes.instanceOf(AppStore).isRequired
}

Related

Programatically redirect user to another page ReactJS [duplicate]

This question already has an answer here:
Problem in redirecting programmatically to a route in react router v6
(1 answer)
Closed last year.
I want to programatically redirect the user to a loading page while I await for a response from the server api. I'm trying to do this inside a class component
The code I've got looks more or less like this:
class App extends Component {
constructor(props){
super(props);
}
handleSubmit = () => {
useNavigate("/loading")
}
}
render() {
return (
<div>
<button onClick={this.handleSubmit}>
Upload!
</button>
</div>
);
}
}
export default App;
The thing is that nothing happens when i click the "Upload!" button. I've read that useNavigate cannot be used inside a class component but I'm not sure how I could implement this differently.
I guess my question is, how can I use useNavigate inside a class component?
EDIT:
Thanks for your responses. I finally decided to convert my code to a function using these steps: https://nimblewebdeveloper.com/blog/convert-react-class-to-function-component
It now works like a charm.
Your clarification is correct, useNavigate() is a hook and therefore can only be used in a functional component. I'm thinking as an alternative you can wrap your App with withRouter, a HOC that gives the wrapping component access to the match, location, and history objects. From there, you can update the location with history.push('/loading').
Please see here for more information on history.
You cannot use useNavigate which is a react hook inside of class component.
you can by the way use react-router-dom which provide different way to manipulate browser url.
Create a functional component as a Wrapper
import { useNavigate } from 'react-router-dom';
export const withRouter = (ClassComponent) => {
const RouterWrapper = (props) => {
const navigate = useNavigate();
return (
<ClassComponent
navigate={navigate}
{...props}
/>
);
};
return RouterWrapper;
};
Then in your App.js, export it by wraping with the functional component
import { withRouter } from './wrapper';
class App extends Component {
constructor(props){
super(props);
}
handleSubmit = () => {
useNavigate("/loading")
}
render() {
return (
<div>
<button onClick={this.handleSubmit}>
Upload!
</button>
</div>
);
}
}
export default withRouter(App);

how to throw a react-alert inside of a function in a class based component

Using react-alert module for alerts
My code looks like this -
index.js:
const options = {
// you can also just use 'bottom center'
position: positions.TOP_CENTER,
timeout: 5000,
offset: '30px',
type: types.ERROR,
// you can also just use 'scale'
transition: transitions.FADE
}
ReactDOM.render(<AlertProvider template={AlertTemplate} {...options}>
<App /></AlertProvider>, document.getElementById('root'));
App.js
class App extends React.Component { //then my state, functions, constructors,
//here is the problem
nextClicked = (e) => {
if (//something) {
if (//something) {
const alert = useAlert();
alert.show("ERROR MESSAGE!!!");
}
} // etc
export default withAlert()(App)
Basically, I am getting the error
Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://reactjs.org/warnings/invalid-hook-call-warning.html for tips about how to debug and fix this problem.
From their docs, it says you can use it with a higher order-component. So, if you
import the withAlert module from react-alert, you can wrap your component when you export it. Again, check the docs on github, this is covered.
Converting the example from the docs to a class component, you get:
import React from 'react'
import { withAlert } from 'react-alert'
class App extends React.component {
constructor(props) {
super(props);
}
render {
return (
<button
onClick={() => {
this.props.alert.show('Oh look, an alert!')
}}
>
Show Alert
</button>
)
}
}
export default withAlert()(App)
Because you wrap the component in the HOC, you get access to the alert prop.

Avoid code repetition - reactJs - javascript

All the time in my app I'm repeating code like this:
if (prodStatus !== Product.Sold) {
this.setState({isSold: false});
} else {
this.setState({isStillThere: false});
}
I've repeated it in my component at least 10x, could I somehow refactor it to looks more nicer or something like that?
Thanks guys
Cheers
Alternately, you could just use
this.setState({isSold: prodStatus === Product.Sold})
And then instead of checking this.state.isStillThere in your code, just check !this.state.isSold.
Here in the React Tutorial, they showcase an example situation similar to what you are dealing with, namely, state that needs to be visible for sub-components but shouldn't be repeated.
They pass the desired property into the props of the sub-component, which is what is generally done (in my experience) with properties that need to be passed down.
Here is some example code:
import React from 'react';
import SubComponent from 'SubComponent';
// MainComponent has prodStatus in props or state.
export default class MainComponent extends React.Component {
render() {
return <div><SubComponent prodStatus={this.state.prodStatus} /></div>;
}
}
Or if you prefer the function syntax (I am not familiar so please let me know if I made a mistake):
import React, { useState } from 'react';
import SubComponent from 'SubComponent';
// MainComponent has prodStatus in props or state.
export default function MainComponent(props) {
const [prodStatus, setProdStatus] = useState(/*prodStatus code*/);
return <div><SubComponent prodStatus={prodStatus} /></div>;
}
You could use ternary operator
prodStatus !== Product.Sold ?
this.setState({ isSold: false }) :
this.setState({ isStillThere: false })
Further refference:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator

React properties/function assignment/declaration

I'm new to React, but not to JS.
Here's a piece of code, that I couldn't understand
// #flow
import React, { Component } from 'react';
import ShowCard from './ShowCard';
import Header from './Header';
class Search extends Component {
state = {
searchTerm: ''
};
props: {
shows: Array<Show>
};
handleSearchTermChange = (event: SyntheticKeyboardEvent & {target: HTMLInputElement}) => {
this.setState({ searchTerm: event.target.value });
};
render() {
return (
<div className="search"></div>
);
}
}
export default Search;
Within the class there are expressions like state = ... and props: {...
Also function definitions like render(){} and handleSearchTermChange = (....
As I recall from all these valid ES6 one is render. How does it work? If I switch the way data assigned to state/props - everything brakes. I assume it's some kind of babel plugin, is it?
Yes, you're right.
The react docs usually defines state via the constructor() {} object. However, in certain projects, we can simply do so via state = {}. This shorthand syntax is possible due to a Babel transpiler called Class properties transform.

Instance of reactJs component to render a component

Can I use an instance of a reactJS component to render a component.
Eg, Let's say my reactJS component is
class myComponent extends Component{
constructor(props){
super(props)
this.state = {
next:false
}
this.alertSomething = this.alertSomething.bind(this);
this.showNext = this.showNext.bind(this);
}
showNext(){
console.log('wow');
console.log(this.state, this, this.state.next);
this.setState({next:true});
}
alertSomething(){
alert('Alert Something')
console.log(this.state, this, this.state.next);
this.setState({next:true});
}
render(){
return(
<div className='column'>
</div>
)
}
}
export default myComponent
Now, inside my another component can I do;
let x = new displayContent.renderComponent();
render(
<x />
//or
<x.render />
)
// I tried both it didn't work, I thought there mush be some other way to achieve this, after all every component is just a javascript object.
Also at the same time, can I call function to make change in its state. Like.
x.someFunction();
where someFunctino is inside that react component, doing setState.
Is it possible? OR am I missing something?
Edit: I clearly understand that when you want to render a react component, you can always do, <component />.
This question is just out of curiosity, can this be done? if not, then why?, I mean how is that different from other javascript objects.
Well, you can use the React.createElement method to render a component:
React.createElement(Component, params)
but with JSX, this is the same:
<Component />
Refer to Multiple components in the React documentation.
This is not how you're supposed to use React. You don't have to handle object instantiations ; React do this for you. Use composition instead.
render() {
return (
<myComponent />
)
}
Also, if you want to set the state of a child component from a parent component, you should probably move the logic in the parent.
Probably you are looking for something like this.
import React, { Component } from "react";
import CamCapture from './CamCapture.js';
export default class ProctorVideoFeed extends Component{
constructor(props) {
super(props);
this.Camera = React.createElement(CamCapture);
}
//this.handleVideoClick = this.handleVideoClick.bind(this);
render(){
return(
<div>
<span>{this.Camera}</span>
<button onClick = {this.Camera.StopRecording}>Stop</button>
</div>
)
}
}
Here StopRecording is a function defined inside CamCapture class.

Categories