【问题标题】:React how to set context from a function. Invalid hook callReact 如何从函数设置上下文。无效挂钩调用
【发布时间】:2023-01-18 23:41:49
【问题描述】:

我无法从不在组件中的函数中检索上下文值。我收到以下异常:

未捕获(承诺)错误:无效挂钩调用。钩子只能是 在函数组件的主体内部调用。这可能发生 由于以下原因之一...

我已经声明了我的上下文。

export const ErrorContext = createContext({})
export const UseErrorContext = () => useContext(ErrorContext)

在我的 App.js 中设置一个提供者

<ErrorContext.Provider value={{ errorMessage }}>
</ErrorContext.Provider>

并且喜欢从这样的函数中设置值。但这会导致上面的异常。此函数位于单独的文件中,并从不同的组件调用。

export const MyFunction = async (id) => {
   const { errorMessage } = UseErrorContext();
   errorMessage = "SOME ERROR MESSAGE";
 }

          

【问题讨论】:

  • MyFunction 更改为 useMyFunction 并仅在顶级组件中调用它。查看rules的hooks

标签: reactjs react-hooks react-context


【解决方案1】:

你将无法这样做: 您不能在反应的渲染阶段之外调用挂钩。

此外,即使您这样调用它,赋值也是局部的,不会影响上下文值。

要实现您想要的行为,您需要:

  • 保存错误消息的状态以及状态设置器
  • 每次错误更改时上下文值都应更改
  • 您应该从调用您的钩子的组件中获取状态设置器
  • 将您的状态设置器作为回调传递给您的异步函数

是这样的:

// context
export let ErrorContext = createContext({})
export let useErrorContext = () => useContext(ErrorContext)

// provider
let [errorMessage, setErrorMessage] = useState();
let value = useMemo(() => ({errorMessage, setErrorMessage}), [errorMessage])
<ErrorContext.Provider value={value}>
  {children}
</ErrorContext.Provider>

// component
let {setErrorMessage} = useErrorContext();


export const myFunction = async (id, setErrorMessage) => {
   setErrorMessage("SOME ERROR MESSAGE");
 }

// later, in an event:
myFunction(id, setErrorMessage);


PS:此解决方案要求您为每个错误消息执行一个提供程序,以便您可以有多个,或者您应该更改抽象。

另一个解决方案看起来像是对我自己的库的提升,但事实并非如此,只是为了展示它解决这个问题的难易程度:

yarn add -D async-states react-async-states


import {useAsyncState, createSource} from "react-async-states"

// myErrorMessage should be unique, or else the library will warn
let myErrorMessageSource= createSource("myErrorMessage");



// in your component
let {state, setState} = useAsyncState(myErrorMessageSource);
// then use the state.data to display it


// in your async function, and your component would react to it
myErrorMessageSource.setState("SOME ERROR MESSAGE");

这只是该库的一个基本用例,请在选择它之前阅读the docs

【讨论】:

    【解决方案2】:

    正如错误所说:

    钩子只能在函数组件的内部调用

    我的建议是创建你的custom hook

    自定义 Hook 是一个 JavaScript 函数,其名称以“use”开头,可以调用其他 Hook。

    现在这是可能的

    export const useMyFunction = async (id) => {
    const { errorMessage } = UseErrorContext();
    ...
    }
    

    确保只在自定义 Hook 的顶层无条件地调用其他 Hook。

    从另一个组件调用自定义挂钩时相同

    【讨论】:

      猜你喜欢
      • 2021-08-18
      • 1970-01-01
      • 2020-10-19
      • 2022-10-04
      • 2021-04-20
      • 1970-01-01
      • 2021-12-07
      • 1970-01-01
      • 2021-04-28
      相关资源
      最近更新 更多