简体   繁体   English

使用 React、React Hooks 的私有路由

[英]Private route using React, React Hooks

Trying to make authenticated route using react hooks, with the snippet below, it appears when i refreshed the page while the token is available it doesn't get picked up in the useEffect at the first render.尝试使用反应钩子创建经过身份验证的路由,使用下面的代码段,当我在令牌可用的情况下刷新页面时,它不会在第一次渲染时在 useEffect 中被拾取。 What i'm doing wrong here我在这里做错了什么

 const AuthRoute = ({ component: Component, ...rest }) => { const context = useContext(AuthStateContext) const token = window.localStorage.getItem('token') useEffect(() => { if (token) { context.setLogin() } console.log("TOKEN ->", token) }, []) return ( <Route {...rest} render={props => ( context.isAuthenticated ? <Component {...props} /> : <Redirect to={{ pathname: "/", state: { from: props.location } }} /> )} /> ) }

I assume context.setLogin() will set context.isAuthenticated to true .我假设context.setLogin()会将context.isAuthenticated设置为true If that's the case, then it explains.如果是这样,那么它解释。

Callback function of useEffect(callback) is always called asynchronously after each render. useEffect(callback)回调函数总是每次渲染异步调用。 As of first render, setLogin() is only called after value of isAuthenticated is read, which at the time of accessing should be false .在第一次渲染时, setLogin()读取isAuthenticated调用,在访问时应为false

So render logic goes to the second branch <Redirect /> which immediately takes user to other place.所以渲染逻辑转到第二个分支<Redirect /> ,它立即将用户带到其他地方。

To achieve this, you can defer the rendering util state of isAuthenticated is decided.为了实现这一点,您可以推迟isAuthenticated的渲染 util 状态决定。

(Here, I assume you want to check and set isAuthenticated once early up in the rendering tree, then broadcast the isAuthenticated through AuthStateContext object for other parts of the app to notice.) (在这里,我假设您想在渲染树的早期检查并设置isAuthenticated一次,然后通过AuthStateContext对象广播isAuthenticatedAuthStateContext用程序的其他部分注意。)

I suggest this pattern:我建议这种模式:

const AuthRoute = ({ component: Component, ...rest }) => {
  const context = useContext(AuthStateContext)
  const [authChecked, setAuthChecked] = useState(false)

  useEffect(() => {
    const token = window.localStorage.getItem('token')
    if (token) context.setLogin()
    setAuthChecked(true)
    console.log("TOKEN ->", token)
  }, [])

  if (!authChecked) return null  // <-- the trick! 

  return (
    <Route
      {...rest}
      render={props => (
        context.isAuthenticated ?
          <Component {...props} />
          : <Redirect to={{
            pathname: "/",
            state: { from: props.location }
          }} />
      )}
    />
  )
}

Side note, if context.setLogin() only asynchronously sets the state of isAuthenticated , then you need to add in a callback or promise pattern like旁注,如果context.setLogin()仅异步设置isAuthenticated的状态,那么您需要添加回调或承诺模式,如

context.setLogin(() => setAuthChecked(true))
// or 
context.setLogin().then(() => setAuthChecked(true))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM