React useContext 抛出 Invalid hook call 错误

React useContext throws Invalid hook call error

我正在尝试使用 useContext 将值从上下文提供者传递给消费者,并在渲染函数之外访问该值。

我的提供商看起来像这样:

export const AppContext = React.createContext();

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

我的消费者是这样的

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

错误是这样的:

挂钩调用无效。钩子只能在函数组件的内部调用。


挂钩仅适用于无状态组件。您正在尝试在 class 组件中使用它。

如果你想使用钩子,它们是为函数组件设计的。像这样:

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

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

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

如果你想在基于 class 的组件中使用它,那么只需在你的 class 中将它设置为静态 contextType,然后你就可以在你的组件中将它与 this.context 一起使用像这样:

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

编辑: 从您的应用程序组件中删除您的上下文并将其放在它自己的组件中。我认为您在导出上下文时遇到了冲突。

因此您的应用程序组件应如下所示:

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;

你的主要组件应该是这样的:

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;

你的上下文组件应该是这样的:

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;

这是一个沙箱,向您展示它的工作原理CodSandbox

这是 Main.js 文件的内容。如果您想使用基于 class 的组件而不是功能组件,请取消注释部分。

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

/** UNCOMMENT TO USE REACT CLASS COMPONENT */
// class Main extends React.Component() {
//   render() {
//     return (
//       <AppContext.Consumer>
//         {value => <div>It's Main component. Context value is ${value.name}</div>}
//       </AppContext.Consumer>
//     );
//   }
// }

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

  return <div>It's Main component. Context value is ${value.name}</div>;
};

export default Main;

这是 App.js 文件的内容。如果您想使用基于 class 的组件而不是功能组件,请取消注释部分。

import React from "react";
import ReactDOM from "react-dom";

import Main from "./Main";

export const AppContext = React.createContext();

/** UNCOMMENT TO USE REACT CLASS COMPONENT */
// export class App extends React.Component() {
//   render() {
//     return (
//       <AppContext.Provider value={{ name: "John" }}>
//         <Main />
//       </AppContext.Provider>
//     );
//   }
// }

const App = () => (
  <AppContext.Provider value={{ name: "John" }}>
    <Main />
  </AppContext.Provider>
);

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

React Hooks 是直接为功能组件实现的,以便使它们有可能成为有状态的。基于 Class 的组件始终是有状态的,因此您必须使用它们自己的 state API.

工作演示可用 here

你得到上面的错误是因为 Hooks 是为了在功能组件内部使用而不是 class 组件,而你试图在 Main 组件的 componentDidMount 中使用它,这是一个 class 组件

您可以使用 useContext 挂钩重写 Main 组件的代码,例如

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

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

或者以不同的方式使用 Context 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 };