首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用react-router-v5和redux-toolkit在登录时重定向页面

使用react-router-v5和redux-toolkit在登录时重定向页面
EN

Stack Overflow用户
提问于 2020-06-02 22:31:36
回答 3查看 4.4K关注 0票数 1

我使用的是react-router-dom v5.2。

登录后,我希望我的页面重定向到/home来自/。登录表在/

当我尝试在没有任何异步功能的情况下执行身份验证时(即,将用户名和密码与react中的硬编码值进行比较),一切工作正常。

但是,当我使用express和mongo执行身份验证时,登录时的重定向停止工作。如果我再次登录,就会发生重定向。受保护的路由仍然有效(如果用户未登录,则重定向到登录页面)。

这是一个关于这个问题的小演示,其中我使用了do auth with express + mongo ie。异步复制。这并不像预期的那样工作。

https://youtu.be/Zxm5GOYymZQ

这是应用程序的链接,在这里我使用硬编码的用户名和密码(都是"test")来执行身份验证。这里没有异步。这可以达到预期的效果。用户名和密码都是"test“。https://poke-zoo.herokuapp.com/

下面是App.js

代码语言:javascript
复制
const ProtectedRoute = ({ component: Component, ...rest }) => {
  const authState = useSelector(selectorAuth)
  // const location = useLocation()
  return (
     {
        if (authState.isUserLoggedIn) {
          return 
        } else {
          return (
            
          )
        }
      }}
    />
  )
}

const App = () => {
  return (
    
      
        
        
          
          
          
           "404 Not found."} />
        
      
    
  )
}

下面是ModalLogin.js

代码语言:javascript
复制
const ModalLogin = props => {
  const { loginModalBool, setLoginModalBool } = props
  const [username, setUsername] = useState("")
  const [password, setPassword] = useState("")

  const dispatch = useDispatch()
  const history = useHistory()

  const attemptLogin = e => {
    e.preventDefault()
    dispatch(tryLogin(username, password))
    history.push("/home")
  }

  return (
    
      
        Login
         setLoginModalBool(!loginModalBool)}>
          close
        
      
      
        
           setUsername(e.target.value)}
            placeholder="username"
          />
           setPassword(e.target.value)}
            type="password"
            placeholder="password"
          />
          
            log in
          
        
      
    
  )
}

下面是authSlice.js

代码语言:javascript
复制
import { createSlice } from "@reduxjs/toolkit"
import axios from "axios"

const initialState = {
  isUserLoggedIn: false,
  username: "",
}

export const authSlice = createSlice({
  name: "auth",
  initialState: initialState,
  reducers: {
    login: (state, action) => {
      const user = action.payload

      if (!user) return alert("Login failed. Incorrect username or password.")

      state.username = user.username
      state.isUserLoggedIn = true
    },
    logout: (state, action) => {
      // window.localStorage.removeItem("loggedInUser")
      state.username = ""
      state.isUserLoggedIn = false
    },
    signup: (state, action) => {
      const user = action.payload
      state.username = user.data.username
      state.isUserLoggedIn = true
    },
  },
})

export const tryLogin = (username, password) => {
  return async dispatch => {
    try {
      const response = await axios.post("/api/auth/login", {
        username: username,
        password: password,
      })

      const user = {
        token: response.headers["auth-token"],
        username: response.data.username,
      }

      // window.localStorage.setItem("token", response.headers["auth-token"])

      dispatch(login(user))
    } catch (e) {
      alert("Incorrect Username/Password.")
    }
  }
}

export const selectorAuth = state => state.auth
export const { login, logout } = authSlice.actions
export default authSlice.reducer

我使用redux-toolkit的react-router有误吗?

下面是Github存储库

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2020-06-06 15:22:03

您的代码没有定义登录后的重定向逻辑。你可以用两种方法来做这件事。

第一:如果你想让你的路由在认证的情况下重定向,你可以为认证定义另一个重定向包装器。

代码语言:javascript
复制
const AuthRoute = ({ component: Component, ...rest }) => {
  const authState = useSelector(selectorAuth)
  const location = useLocation()
  return (
     {
        if (!authState.isUserLoggedIn) {
          return 
        } else {
          return (
            
          )
        }
      }}
    />
  )
}

const App = () => {
  return (
    
      
        
        
          // It is for login users to redirect to home page
          
          
          
           "404 Not found."} />
        
      
    
  )
}

第二:另一种方法可以使用history.push()或history.replace()进行强制处理:

代码语言:javascript
复制
const Layout = () => {
  const authState = useSelector(selectorAuth);
  const history = useHistory();

  useEffect(() => {
    // if isUserLoggedIn turned to true redirect to /home
    if (authState.isUserLoggedIn) { 
      history.push("/home");
    }
  }, [authState.isUserLoggedIn]); // triggers when isUserLoggedIn changes

  return (
    
      
      
      
       "404 Not found."} />
    
  );
};

const App = () => {
  return (
    
      
        
        
      
    
  );
};

为什么你的代码不能工作?看看下面的代码:

代码语言:javascript
复制
"404 Not found."} />

它能做什么?它会检查您的浏览器路径,并从上到下检查它是否与给定的路由规则匹配。如果Route path匹配,则它呈现组件,如果不匹配,则继续向下访问每个Route,直到它与您的404匹配。

因此,回到您的情况;当您登录时,您没有离开"/“路径。因为没有实现离开"/“路径的逻辑。因此,即使它已通过身份验证,它也会再次与登录页面匹配。它与路由路径(登录页面)匹配并停留在那里。它不会继续并在ProtectedRoute上尝试您的逻辑。

票数 7
EN

Stack Overflow用户

发布于 2021-02-25 04:52:08

当前接受的答案修复了您的问题,但没有正确确定您遇到问题的原因。所以我想为你(以及其他阅读这篇文章的人)解释一下。

问题:重定向太快

代码语言:javascript
复制
const attemptLogin = e => {
  e.preventDefault()
  dispatch(tryLogin(username, password))
  history.push("/home")
}

此代码将调度tryLogin和立即呼叫history.push("/home")。它不等待调度的操作完成并更新存储。

当你调用history.push("/home")您的应用程序加载ProtectedRoute对于组件Home。在ProtectedRoute使用选择器检查authState.isUserLoggedIn。如果是false,然后重定向到"/"

因此,如果您重定向到"/home"的值之前authState.isUserLoggedIn已更新,则您最终将被重定向回"/"而不是能够查看Home组件。

这就是为什么异步身份验证会有这些问题的原因:

当我尝试在没有任何异步功能的情况下执行身份验证时(即,将用户名和密码与react中的硬编码值进行比较),一切工作正常。

但是,当我使用express和mongo执行身份验证时,登录时的重定向停止工作。

解决方案:重定向前等待

您需要等待authState更新之前重定向到受保护的路由。

有很多方法可以做到这一点,但一般来说,我们希望使用选择器来侦听发布到redux状态的更改。这里有一种方法,它使用ModalLogin有条件地呈现Redirect组件。我还建议为登录错误包括某种类型的选择器,以防分派完成解决但登录不成功。您可能希望在模式中向用户显示一条错误消息。

代码语言:javascript
复制
const ModalLogin = props => {
  const { loginModalBool, setLoginModalBool } = props
  const [username, setUsername] = useState("")
  const [password, setPassword] = useState("")

  const dispatch = useDispatch()
  const history = useHistory()
  
  // Look at the authState from redux.  This value will automatically update.
  const authState = useSelector(selectorAuth)

  const attemptLogin = e => {
    e.preventDefault()
    dispatch(tryLogin(username, password))
    // don't redirect here anymore
  }

  // Once logged in, render the redirection
  if ( authState.isUserLoggedIn ) {
     return (
       
     );
  }
  
  // Otherwise, render the modal
  return (
    /* your current code */
  )
}
票数 1
EN

Stack Overflow用户

发布于 2020-06-05 03:27:35

老实说,我所做的是在用户登录时使用普通的老式javascript来更改位置。

代码语言:javascript
复制
window.location = "/redirect"
票数 -2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62154408

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档