0

I'm fairly new to React and am currently working on changing a functional component to a class, however I'm receiving the following error:

Error: Invalid hook call. Hooks can only be called inside of the body of a function component.

This appears to relate to line 11:

const { choices, setChoices } = useContext(ChoicesContext); 

Any help would be much appreacited.

import React, { useContext } from "react"; import { Link } from "react-router-dom"; import CategoryData from "./data/CategoryData"; import { ChoicesContext } from "../context/ChoicesProvider"; import { ReactComponent as Logo } from '../images/logo.svg'; import { ReactComponent as WaterTechLogo } from '../images/water-tech-logo.svg'; class Applications extends React.Component { render() { const { choices, setChoices } = useContext(ChoicesContext); return ( <> <Link to="/"> <Logo className="Logo" /> </Link> <WaterTechLogo className="WaterTechLogo" /> <div className="pageLinks"> <div className="breadcrumb">Applications</div> <div className="backBtn"></div> </div> <div className="applications wrapper d-md-flex"> <aside> <h2>Select an<br />Application</h2> </aside> <main> <div id="applicationsList"> {CategoryData.map((cat, i) => ( <div key={i} className="application"> <Link onClick={() => setChoices({ ...choices, category: cat.name })} to={{ pathname: "/waterType", name: cat.name, }} > <img src={cat.imageURL} alt={cat.name} /> <h4 className="appTitle">{cat.name}</h4> </Link> </div> ))} </div> </main> </div> </> ); } } export default Applications; 

2 Answers 2

2

The error clearly states that hooks can only be called inside functional component. However your Applications component is a class component and you are trying to use useContext in it.

Convert it into a functional component like

const Applications = () => { const { choices, setChoices } = useContext(ChoicesContext); return ( <> <Link to="/"> <Logo className="Logo" /> </Link> <WaterTechLogo className="WaterTechLogo" /> <div className="pageLinks"> <div className="breadcrumb">Applications</div> <div className="backBtn"></div> </div> <div className="applications wrapper d-md-flex"> <aside> <h2>Select an<br />Application</h2> </aside> <main> <div id="applicationsList"> {CategoryData.map((cat, i) => ( <div key={i} className="application"> <Link onClick={() => setChoices({ ...choices, category: cat.name })} to={{ pathname: "/waterType", name: cat.name, }} > <img src={cat.imageURL} alt={cat.name} /> <h4 className="appTitle">{cat.name}</h4> </Link> </div> ))} </div> </main> </div> </> ); } export default Applications; 

The other solution is to use Context like like in class components by defining a static contextType property

class Applications extends React.Component { static contextType = ChoicesContext; render() { const { choices, setChoices } = this.context; return ( <> <Link to="/"> <Logo className="Logo" /> </Link> <WaterTechLogo className="WaterTechLogo" /> <div className="pageLinks"> <div className="breadcrumb">Applications</div> <div className="backBtn"></div> </div> <div className="applications wrapper d-md-flex"> <aside> <h2>Select an<br />Application</h2> </aside> <main> <div id="applicationsList"> {CategoryData.map((cat, i) => ( <div key={i} className="application"> <Link onClick={() => setChoices({ ...choices, category: cat.name })} to={{ pathname: "/waterType", name: cat.name, }} > <img src={cat.imageURL} alt={cat.name} /> <h4 className="appTitle">{cat.name}</h4> </Link> </div> ))} </div> </main> </div> </> ); } } export default Applications; 
Sign up to request clarification or add additional context in comments.

4 Comments

As a note, there is a library that will let you add hooks to class components: github.com/salvoravida/react-universal-hooks, though I wouldn't necessarily recommend it
@ZacharyHaber yes, things that can be done with hooks can also be done with class components so it isn't essential to use a library just to use hooks in class components. Its not even recommended in react. Otherwise we wouldn't be seeing such errors being thrown :-)
Not necessarily true (that all things done with hooks can be done with class components), there is better composability and re-usability that hooks provide, which is the only reason I'd even contemplate using it on a component I can't convert to hooks and didn't want to wrap with a million HOCs for the hooks of interest. useMemo is also very convenient at times and much easier than doing the equivalent in a class component.
Sure, Its actually up to the user too. Sometimes functional components can be easier to use and sometimes class components.
0

You can't use hooks inside a class component. Only in function components.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.