reactjs 为什么Context.Provider提供的函数不更改来自同一上下文的值?

xxslljrj  于 2023-03-22  发布在  React
关注(0)|答案(1)|浏览(110)

我想写一个简单的AuthProvider。为此,我有上下文:

type ContextType = {
    auth: string
    setAuth: Dispatch<SetStateAction<string>>
}  
const AuthContext = createContext({} as ContextType)

实际上是提供者本身

type Props = {
    children: ReactNode
}

export function AuthProvider({children}: Props):JSX.Element {
   const [auth, setAuth] = useState<string>("") 
   const value = useMemo(() => ({
        auth, setAuth
   }), [auth]);
  
   console.log("inside - ",auth)
   return (
      <AuthContext.Provider value={value}>
      {children}
      </AuthContext.Provider>
   )
}
  
export function useAuth(): ContextType {
    return useContext(AuthContext)
}

问题是saveAuth不会改变值。也就是说,当我收到一个令牌时,我会尝试保存它:

const { auth,setAuth } = useAuth();
const response = await getToken(data);
if (response) {
    const accessToken = response.access
    saveAuth(accessToken)
}

现在在Requier中:

const RequierAuth = () => {
    const { auth } = useContext(AuthContext) as AuthContextType;
    const location = useLocation();
    console.log("require : ", auth)
    return (
        auth != undefined && auth !== ""?<Outlet/> : <Navigate to = "/auth" state = {{from:location}} replace />
    );

}

该值始终是默认值,即""。虽然我收到并保存的令牌是正确的。该函数的错误是什么?
我可能错了,但是Require Auth有问题。例如,我将日志添加到:

console.log("inside - ",auth)
    return (
      <AuthContext.Provider value={value}>
      {children}
      </AuthContext.Provider>
    )

而在调用setAuth函数后,值发生了变化,现在我转到RequireAuth保护的页面,日志显示auth现在为空,我不明白为什么会这样?

索引

root.render(
  <React.StrictMode>
     <BrowserRouter>
     <AuthProvider>
      <App />
     </AuthProvider>
    </BrowserRouter>
  </React.StrictMode>
);

app

<div className="App">
      <Routes>
          <Route path="/" element={<Layout />}>
            <Route path="auth" element={<SignInForm />} />
            <Route path="reg" element={<SignUpForm />} />
            <Route element = {<RequierAuth/>}>
                <Route path="home" element={<Home />} />              
            </Route>
          </Route>
        </Routes>
</div>

重现错误

1)https://codesandbox.io/s/zen-wildflower-hxkg42?file=/src/auth.tsx
2)go to /auth
3)input some data -> submit -> check console
4)go /home and back navigate to the page /auth. Although this should not be the case. You can change the initial value in useState and it will work fine
brccelvz

brccelvz1#

在你的代码中试试这个:
PS.如果你没有使用typescript,只需要删除类型声明:D

type Props = {
  children: ReactNode
}
type ContextType = {
  auth: string
  setAuth: Dispatch<SetStateAction<string>>
  // add here other variables and functions 
  // you want to export with your context
}

const AuthContext = createContext({} as ContextType)

export function AuthProvider({
  children
}: Props):JSX.Element {
  // using string but could be whatever type your auth varable is
  const [auth, setAuth] = useState<string>('') 

  return (
    <AuthContext.Provider
      value={
        useMemo(() => ({
          auth,
          setAuth,
          // add here other variables/functions exported
          // E.g.: currentTheme, setCurrentTheme
          // loading, setLoading, etc...
        }), [
          auth
          // add here other variables those values changes
          // E.g.: currentTheme, loading, etc...
        ])
      }
    >
    ...
    {children}
    ...
    </AuthContext.Provider>
  )
}

export function useAuth(): ContextType {
  return useContext(AuthContext)
}

现在,您需要在您想要访问上下文数据的所有组件之上的其他位置使用提供程序。
例如:

// index.tsx
import {AuthProvider} from '..../auth.tsx'

....

return (
  <AuthProvider>
    <MyAppComponent />
  </AuthProvider>
)

然后在MyAppComponent中,只需调用useAuth函数即可访问所有导出的变量和函数
例如:

import {useAuth} from '..../auth.tsx'

...

const {
  auth,
  setAuth
} = useAuth()

...

相关问题