Home > Back-end >  useState with useContext in Typescript
useState with useContext in Typescript

Time:05-29

Lets say I have a basic setup for checking whether a user is logged in or not:

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

In my App.tsx I want to create a useState hook so that I can manage the state of my context throughout my application:

//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>

So as far as I can see I'll only ever need either the name of the logged in user, or set the state of the context to null if I want to deny access to certain pages. Now the issue is that typescript is yelling at me here, specifically in the value of the Provider:

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

I can force cast the value as follows:

value={{context, setContext} as any}

But that doesn't seem like a particularly elegant 'typescripty' solution.

Any help is appreciated!

CodePudding user response:

You've typed your context as:

string | null

But then you provide a value for that context of (approxiamately) type:

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

So if you want the state setter in your context, then it needs to be part of the context's type:

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

CodePudding user response:

Based on Alex's answer I came up with a tweak that works for me:

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

And then in 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>
  • Related