1

I know that hooks are the oposite of a class component - don't get me wrong, I just don't know how a simple line of code can make this error appear and what I have to change in that line to make it work in an class component. I got the following example which works very well with .jsx type of file and with functional components.

Codesandbox example one

This code is just a simple way of share a state between components. So we got the file extendDiv where we have our state and a simple function to change that state; then we have a global file, to got that state and distribute it to all of our components: son (filho) and father (pai). In the codesandbox example one it works just fine, but when I do the exactly same thing but with a class component in the App.jsx and with some typescript files, it gives me the following error in the following code:

global.isDivExtended = extendDiv();
//Invalid hook call. Hooks can only be called inside of the body of a function component.

You can see all the code and try it here: Codesandbox example two

What I should do here to make it work in an class component? I've already tried to bind the global and to use the this... Thank you very much.

Pedro Relvas
  • 678
  • 7
  • 19

1 Answers1

3

React hooks can't be called from class components.

You can either convert said class component to a function component, or leave it as a class component and manage state the good ol' class-component way. Converting to a function should be preferred.

It seems the sandbox doesn't have all the files, so I can't know for sure, but i believe this might work:

import * as React from "react";
import "./styles.css";
import Father from "../src/components/father";
import global from "./global";
import extendDiv from "./extendDiv";

function App(props) {
  let [dateVar, setDateVar] = React.useState({ date: new Date() })
  global.isDivExtended = extendDiv();

  return (
      <>
        <Father></Father>
      </>
  )
}

export default App;

Alternatively, you can write a higher-order component wrapper for your hook, so that you can pass the logic of a hook as a prop to your class component, as explained here. However, if possible, I would suggest avoiding it; it's messy and it's harder to test. Function components are way more fun to write (and read), plus it seems they are the future of React.

pitamer
  • 905
  • 3
  • 15
  • 27
  • 1
    Hi. Thank you for the answer. The problem here is that I have to use this logic in an old project that has class components, if it was for me I would change it to hooks right way :D. I'm just wonder if there is no way to change this line "global.isDivExtended = extendDiv();" for something else to make it work on an class component. And to be honest I don't know what "screams" hooks in this simple line. Thank you again @pitamer – Pedro Relvas Aug 09 '20 at 16:49
  • 1
    The problem is in **extendDiv.tsx**, in line 4: `const [isDivExtended, setIsDivExtended] = useState(false)`. The variable `isDivExtended` is a state declared by a hook, and it has a matching function to set it to a new value. Therefore, you can't use it in a class component. If you must use only class components for this project, I would suggest initializing `isDivExtended` as a state inside the `this.state` of **App.tsx**. – pitamer Aug 09 '20 at 17:03
  • 2
    Another problem is that custom hooks really should keep the `useXyz` naming pattern to avoid confusion (as it appears to have caused already). You really should rename the hook, if you can. – Chris Aug 09 '20 at 17:53