4

我有一个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'.

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

const SetBookedBatchContext = createContext(null)

这样 TypeScript 就不会抱怨了。

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

1 回答 1

5

React.createContext和的返回类型由您传入的初始值React.useState推断确定。

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

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

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

2.) 在您的自定义 Hook 中断言useBookedBatchsetBookedBatch不是: 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之后可以在没有断言的情况下调用 then:

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

操场上的样品

于 2020-03-16T21:33:45.243 回答