如何在 createContext 中为 TypeScript 初始化 useState 的 set 函数?

IT技术 reactjs typescript react-hooks use-state
2021-05-08 22:48:02

我有一个Provider通过两个contexts.

const BookedBatchContext = createContext({})
const SetBookedBatchContext = createContext(null)

const initialState = {
  id: null
}

Provider如下所示:

export const BookedBatchProvider = ({ children }: { children: any }) => {
  const [bookedBatch, setBookedBatch] = useState(localState ||initialState)

  return (
    <SetBookedBatchContext.Provider value={setBookedBatch}>
      <BookedBatchContext.Provider value={bookedBatch}>
        { children }
      </BookedBatchContext.Provider>
    </SetBookedBatchContext.Provider>
  )
}

通过自定义钩子,我使setBookedBatch其他组件可用:

export const useBookedBatch = () => {
  const bookedBatch = useContext(BookedBatchContext)
  const setBookedBatch = useContext(SetBookedBatchContext)

  return { bookedBatch, setBookedBatch }
}

尝试使用该setBookedBatch函数时,在给定组件中出现以下错误:

setBookedBatch(selectedBatch)

错误:

TS2721: Cannot invoke an object which is possibly 'null'.

由于useState函数的setter是我没有创建的函数,所以我在创建上下文的时候不知道怎么初始化:

const SetBookedBatchContext = createContext(null)

这样 TypeScript 就不会抱怨了。

  1. 如何知道 setter 函数的初始值?
  2. 如果我不提供任何类型,如何避免 TS 抱怨空值?
1个回答

返回类型React.createContext,并React.useState通过推理从确定的初始值,你通过。

1.) 您可以通过手动指定泛型类型来创建正确的上下文类型:

const SetBookedBatchContext = createContext<null | React.Dispatch<React.SetStateAction<State>>>(null)

注意: setter foruseState有 type React.Dispatch<React.SetStateAction<State>>, whereState是什么localState || initialState

2)断言在自定义挂钩useBookedBatch,那setBookedBatch不是 null

export const useBookedBatch = () => {
  const bookedBatch = useContext(BookedBatchContext)
  const setBookedBatch = useContext(SetBookedBatchContext)
  if (setBookedBatch === null) throw new Error() // this will make setBookedBatch non-null
  return { bookedBatch, setBookedBatch }
  // returns: { bookedBatch: {}; setBookedBatch: React.Dispatch<React.SetStateAction<State>>; }
}

3.) 然后setBookedBatch可以在没有断言的情况下调用:

const App = () => {
  const { setBookedBatch } = useBookedBatch()
  useEffect(() => { setBookedBatch({ id: "foo" }) }, [])
}

操场上的样品