首页 > 解决方案 > 无法从上下文提供者获取钩子

问题描述

我正在 基于这种方法使用上下文提供程序设置这个自定义钩子

const mainState = (initial: number | null = null) => {
  const [edit, setEdit] = React.useState<number | null>(initial)

  return {
    edit,
    clear: () => setEdit(null)
  }
}

const MainContext = React.createContext<ReturnType<typeof mainState> | null>(null)

export const useMainContext = () => React.useContext(MainContext)

export function MainProvider({ children }: { children: React.ReactNode }) {
  return (
    <MainContext.Provider value={mainState()}>{children}</MainContext.Provider>
  )
}

然后我将整个应用程序包装在提供程序中

import React from 'react'
import ReactDom from 'react-dom'
    
import { MainProvider } from './store'
import { App } from './app'
    
ReactDom.render(
  <MainProvider>
    <App />
  </MainProvider>,
  document.getElementById('root')
)

但是当我尝试获取钩子 TypeScript 错误时

Property 'edit' does not exist on type '{ edit: number | null; clear: () => void; } | null'

import * as React from 'react'
import { useMainContext } from './store'
    
export const App = () => { 
  const { edit } = useMainContext()
  ...
}

标签: reactjstypescriptreact-context

解决方案


正如 Typescript 告诉您的那样,您的上下文类型可以是null{ edit: number | null; clear: () => void; }

记住您最初将其设置为:const MainContext = React.createContext<ReturnType<typeof mainState> | null>(null).

你不能解构 null 所以这就是 Typescript 不高兴的原因。要么你不使用解构:

const context = useMainContext()
context?.edit

或者您将上下文设置为具有编辑默认值的不同值。


我刚刚注意到 mainState 正在使用 useState 但 mainState 似乎既不是自定义反应钩子也不是组件。反应文档指出自定义反应钩子应该以use. 并且必须在另一个自定义反应钩子或组件中使用钩子。

因此,修复代码的一种方法是:

const useMainState = (initial: number | null = null) => { // this is now a custom react hook
  const [edit, setEdit] = React.useState<number | null>(initial)

  return {
    edit,
    clear: () => setEdit(null)
  }
}

export function MainProvider({ children }: { children: React.ReactNode }) {
  // it's called in a component, Ok
  const mainState = useMainState()
  return (
    <MainContext.Provider value={mainState}>{children}</MainContext.Provider>
  )
}

现在 React 可以跟踪你的状态。这就是为什么在 if 之后永远不要使用钩子也很重要的原因。在一个组件中必须始终使用相同数量的钩子。

这与您所做的非常相似,但是您在道具中进行了调用,即使它有效,也不是很好的设计。


推荐阅读