Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React useContext throws Invalid hook call error

I am trying to pass a value from a context provider to a consumer using useContext and access the value outside of the render function.

My provider looks like so:

export const AppContext = React.createContext();

export class App extends React.Component(){
    render(){
        <AppContext.Provider value={{ name: 'John' }} ><Main /></AppContext>   
    }
}

My consumer looks like so

import React, { useContext } from 'react';
import { AppContext } from './App';

export class Main extends React.Component(){
    componentDidMount(){
        const value = useContext(AppContext);
    }
    render(){
        return (
            <div>Main Component</div>
        )
    }
}

The error is this:

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


like image 793
Singh Avatar asked Apr 29 '19 03:04

Singh


People also ask

How do you fix error invalid hook call Hooks can only be called inside of the body of a function component?

If the error persists, try to delete your node_modules and package-lock. json (not package. json ) files, re-run npm install and restart your IDE. The error is often caused by having multiple versions of react in the same project.

What does the useContext hook return when called?

The hook returns the value of the context: value = useContext(Context) . The hook also makes sure to re-render the component when the context value changes.

How do you use useContext in React Hooks?

Syntax: const authContext = useContext(initialValue); The useContext accepts the value provided by React. createContext and then re-render the component whenever its value changes but you can still optimize its performance by using memoization.

Is useContext a hook?

“useContext” hook is used to create common data that can be accessed throughout the component hierarchy without passing the props down manually to each level. Context defined will be available to all the child components without involving “props”.


2 Answers

If you want to use hooks they are designed for function components. Like so:

import React, { useContext } from 'react';
import { AppContext } from './App';

const Main = () => {
  const value = useContext(AppContext);

  return(
    <div>Main Component</div>
  );
}

If you want to use it in a class based component then just set it as a static contextType in your class and then you can use it with this.context in your component like so:

import React from 'react';
import { AppContext } from './App';

class Main extends React.Component(){

  static contextType = AppContext;

  componentDidMount(){
    const value = this.context;
  }
  render(){
    return (
      <div>Main Component</div>
    )
  }
}

Edit: Remove your context from your app component and place it in its own component. I think you are receiving conflicts in your exporting of your context.

so your app component should look like:

import React from "react";
import Context from "./Context";
import Main from "./Main";

class App extends React.Component {
  render() {
    return (
      <Context>
        <Main />
      </Context>
    );
  }
}

export default App;

Your main component should be like:

import React from "react";
import { AppContext } from "./Context";

class Main extends React.Component {
  static contextType = AppContext;

  render() {
    return <div>{this.context.name}</div>;
  }
}

export default Main;

and your context component should be like:

import React from "react";

export const AppContext = React.createContext();

class Context extends React.Component {
  state = {
    name: "John"
  };

  //Now you can place all of your logic here
  //instead of cluttering your app component
  //using this components state as your context value
  //allows you to easily write funcitons to change
  //your context just using the native setState 
  //you can also place functions in your context value
  //to call from anywhere in your app
  render() {
    return (
      <AppContext.Provider value={this.state}>
        {this.props.children}
      </AppContext.Provider>
    );
  }
}

export default Context;

Here is a sandbox to show you it working CodSandbox

like image 198
Steve K Avatar answered Oct 20 '22 11:10

Steve K


You get the above error because Hooks are meant to be used inside functional components and not class component whereas you try to use it within componentDidMount of Main component which is a class component

You can rewrite your code for Main component using useContext hook like

import React, { useContext } from 'react';
import { AppContext } from './App';

export const Main =() =>{
    const value = useContext(AppContext);
    return (
        <div>Main Component</div>
    )
}

or use Context in a different way with class like

import React from 'react';
import { AppContext } from './App';

class Main extends React.Component {
    componentDidMount(){
        const value = this.context;
        // use value here. Also if you want to use context elsewhere in class
        // you can use if from this.context
    }
    render(){
        return (
            <div>Main Component</div>
        )
    }
}

Main.contextType = AppContext;

export { Main };
like image 35
Shubham Khatri Avatar answered Oct 20 '22 10:10

Shubham Khatri