如何在将状态变量作为提供者值传递时使用TypeScript和createContext?

huangapple go评论68阅读模式
英文:

How to use typescript with createContext when passing state variables as the provider value?

问题

我正在尝试在使用 TypeScript 时使用 createContext。我正在创建一个名为 "NavContext" 的上下文包装类,并将状态变量作为值传递给提供程序。

以下是代码:

export const NavContext = createContext<any>();

const NavBar: React.FC<ReactNode | undefined> = ({ children }) => {
    const [isDrawerOpen, setIsDrawerOpen] = useState(false);

    return (
        <NavContext.Provider value={{ isDrawerOpen, setIsDrawerOpen }}>
            <AppBar position="static">{children}</AppBar>
        </NavContext.Provider>
    );
};

但我在 "createContext()" 下方得到了插入符号 "^^^^^^",并且收到了 TypeScript 错误消息:

TS2554: 期望 1 个参数,但得到 0 个。

请指导我如何解决此错误,因为在没有 TypeScript 的情况下,此代码运行正常。

英文:

I am trying to use typescript with createContext. I am making a context wrapper class NavContext and passing state variables as value to the provider.

Here is the code:

export const NavContext = createContext();

const NavBar:ReactFC&lt;ReactNode | undefined&gt;= ({ children }) =&gt; {
    const [isDrawerOpen, setIsDrawerOpen] = useState(false);

    return (
        &lt;NavContext.Provider value={{ isDrawerOpen, setIsDrawerOpen }}&gt;
            &lt;AppBar position=&quot;static&quot;&gt;{children}&lt;/AppBar&gt;
        &lt;/NavContext.Provider&gt;
    );
};

But I get caret symbol ^^^^^^ beneath createContext() and get typescript error as

TS2554: Expected 1 arguments, but got 0.

Please guide me on how to resolve this error as without typescript this code worked fine.

答案1

得分: 2

以下是您提供的代码的翻译部分:

设置 NavbarContext.tsx

type NavContextType = {
  isDrawerOpen: boolean;
  setIsDrawerOpen: React.Dispatch<React.SetStateAction<boolean>>;
}

export const NavContext = createContext<NavContextType | null>(null);

type ProviderType = {
  children: React.ReactNode;
};

export default function NavBarStateProvider({ children }: ProviderType) {
  const [isDrawerOpen, setIsDrawerOpen] = useState(false);

  return (
    <NavContext.Provider value={{ isDrawerOpen, setIsDrawerOpen }}>
      {children}
    </NavContext.Provider>
  );
}

用于使用上下文的自定义钩子,useNavContext.tsx

export default function useNavContext() {
  const context = useContext(NavContext);
  if (!context) {
    throw new Error("useNavContext must be used within a NavBarStateProvider");
  }
  return context;
}

请注意,这是您提供的代码的翻译部分,我没有提供其他内容。

英文:

This is the way I set up context with TS, by providing a default value:

Set up NavbarContext.tsx:

type NavContextType = {
  isDrawerOpen: boolean;
  setIsDrawerOpen: React.Dispatch&lt;React.SetStateAction&lt;boolean&gt;&gt;;
}

export const NavContext = createContext&lt;NavContextType | null&gt;(null);

type ProviderType = {
  children: React.ReactNode;
};

export default function NavBarStateProvider({ children }: ProviderType) {
  const [isDrawerOpen, setIsDrawerOpen] = useState(false);

  return (
    &lt;NavContext.Provider value={{ isDrawerOpen, setIsDrawerOpen }}&gt;
      {children}
    &lt;/NavContext.Provider&gt;
  );
}

Custom hook to use the context, useNavContext.tsx:

export default function useNavContext() {
  const context = useContext(NavContext);
  if (!context) {
    throw new Error(&quot;useNavContext must be used within a NavBarStateProvider&quot;);
  }
  return context;
}

答案2

得分: 0

问题是上下文可能被消耗而不一定是 Provider 的子级。即使您的应用程序在任何地方都不这样做,您仍需要通过将默认上下文值传递给.createContext来使 TypeScript 快乐(因为上下文值类型似乎具有其中的状态设置器,我会假设总会有一个提供者 - 因为您不能在 React 组件的上下文之外具有状态设置器。)

一种选择是向 createContext 传递一个无意义的参数(只是因为它是必需的),并告诉 TypeScript 类型不匹配是可以的。还要注意,createContext 也应该有一个泛型参数。

type NavContextType = {
  isDrawerOpen: boolean;
  setIsDrawerOpen: React.Dispatch<React.SetStateAction<boolean>>;
};
export const NavContext = createContext<NavContextType>(undefined!);
英文:

The problem is that contexts can be consumed without necessarily being a child of a Provider. Even if your app doesn't do this anywhere, you need to make TypeScript happy by passing the default context value to .createContext. (Because the context value type looks to have a state setter in it, I'd assume that there will always be a provider - because you can't have a state setter outside the context of a React component.)

One option is to pass a meaningless argument to createContext (just because it's required) and tell TypeScript that it's OK that the type doesn't match. Also note that createContext should have a generic argument as well.

type NavContextType = {
  isDrawerOpen: boolean;
  setIsDrawerOpen: React.Dispatch&lt;React.SetStateAction&lt;boolean&gt;&gt;;
};
export const NavContext = createContext&lt;NavContextType&gt;(undefined!);

答案3

得分: 0

你应该清晰地定义 provider 和 context 的类型。

interface ProviderProps {
  children: React.ReactNode
}

interface ContextValue {
  isDrawerOpen: boolean;
  setIsDrawerOpen: () => void;
}

export const NavContext = createContext<ContextValue>(
  null as unknown as ContextValue
)

const NavBar = ({ children }: ProviderProps) => {
    const [isDrawerOpen, setIsDrawerOpen] = useState(false);

    return (
        <NavContext.Provider value={{ isDrawerOpen, setIsDrawerOpen }}>
            <AppBar position="static">{children}</AppBar>
        </NavContext.Provider>
    );
};
英文:

You should define the types for provider and context clearly.

interface ProviderProps {
  children: React.ReactNode
}

interface ContextValue {
  isDrawerOpen: boolean;
  setIsDrawerOpen: () =&gt; void;     
}

export const NavContext = createContext&lt;ContextValue&gt;(
  null as unknown as ContextValue
)

const NavBar = ({ children }: ProviderProps) =&gt; {
    const [isDrawerOpen, setIsDrawerOpen] = useState(false);

    return (
        &lt;NavContext.Provider value={{ isDrawerOpen, setIsDrawerOpen }}&gt;
            &lt;AppBar position=&quot;static&quot;&gt;{children}&lt;/AppBar&gt;
        &lt;/NavContext.Provider&gt;
    );
};

huangapple
  • 本文由 发表于 2023年1月6日 14:39:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/75027752.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定