Typescript 中的 useState 和 useContext

问题描述 投票:0回答:3

假设我有一个基本设置来检查用户是否登录:

import { createContext } from "react";
const UserContext = createContext<string | null>(null)
export default UserContext

在我的 App.tsx 中,我想创建一个 useState 挂钩,以便我可以管理整个应用程序中的上下文状态:

//Context
const [context, setContext] = useState<string | null>(null)

  <UserContext.Provider value={{context, setContext}}>

    <Routes>

      <Route path="/" element={<Home/>}/> 
      <Route path="/login" element={<Login/>}/> 
      <Route path="/register" element={<Register/>}/> 
      <Route path="/admin" element={<Admin/>}></Route>

    </Routes>  

  </UserContext.Provider>

据我所知,我只需要登录用户的名称,或者如果我想拒绝访问某些页面,则将上下文的状态设置为空。现在的问题是打字稿在这里对我大喊大叫,特别是在 Provider 的值上:

Type '{ context: string | null; setContext: 
React.Dispatch<React.SetStateAction<string | null>>; }' is not assignable to type 'string'.ts(2322)

我可以按如下方式强制转换值:

value={{context, setContext} as any}

但这似乎不是一个特别优雅的“打字”解决方案。

如有任何帮助,我们将不胜感激!

typescript use-state provider use-context createcontext
3个回答
12
投票

根据亚历克斯的回答,我想出了一个适合我的调整:

type UserContextType = {
     context: string | null,
     setContext: React.Dispatch<React.SetStateAction<string | null>>
 }

const iUserContextState = {
    context: null,
    setContext: () => {}
}

const UserContext = createContext<UserContextType>(iUserContextState)

export default UserContext

然后在 App.tsx 中:

//Context
const [context, setContext] = useState<string | null>(null)

  <UserContext.Provider value={{context, setContext}}>

    <Routes>

      <Route path="/" element={<Home/>}/> 
      <Route path="/login" element={<Login/>}/> 
      <Route path="/register" element={<Register/>}/> 
      <Route path="/admin" element={<Admin/>}></Route>

    </Routes>  

  </UserContext.Provider>

5
投票

您输入的上下文为:

string | null

但是你为该上下文提供了一个(大约)类型的值:

{ context: string | null, setContext: (newString) => void }

因此,如果您希望在上下文中使用状态设置器,那么它需要成为上下文类型的一部分:

const UserContext = createContext<{
  context: string | null,
  setContext: (newValue) => void
}>({
  context: null,
  setContext: () => undefined
})

0
投票

如果你想保留

useState
的数组作为返回值,这是一个正确的 TypeScript 解决方案:

import React, { FC, createContext, useContext, useState } from 'react';

// Change shape of this object to your/app needs
const initialAppState = {
  userName: "",
};

export type AppState = typeof initialAppState;

type ContextType = [AppState, React.Dispatch<React.SetStateAction<AppState>>];
const AppStateContext = createContext<ContextType>([] as unknown as ContextType);

type Props = {
  appState?: AppState;
};

/**
 * Provider to pass state to the React application
 */
export const AppStateProvider: FC<React.PropsWithChildren<Props>> = (props) => {
  const { appState = null } = props;
  const useStateRetValue = useState<AppState>(appState == null ? initialAppState : appState);

  return <AppStateContext.Provider value={useStateRetValue}>{props.children}</AppStateContext.Provider>;
};
AppStateProvider.defaultProps = {
  appState: undefined,
};

/**
 * Hook to access application state
 */
export const useAppStateContext = (): ContextType => useContext<ContextType>(AppStateContext);

提供商使用情况:

  <AppStateProvider>

    <Routes>

      <Route path="/" element={<Home/>}/> 
      <Route path="/login" element={<Login/>}/> 
      <Route path="/register" element={<Register/>}/> 
      <Route path="/admin" element={<Admin/>}></Route>

    </Routes>  

  </AppStateProvider>

挂钩用法:


const [appState, setAppState] = useAppStateContext();

console.log(appState.userName);

useEffect(() => {
  setAppState({ userName: "John Doe" });
}, [setAppState]);

// ...or...

const [, setAppState] = useAppStateContext();

// ...or...

const [appState] = useAppStateContext();

© www.soinside.com 2019 - 2024. All rights reserved.