reactjs - 使用 react-router-v5 和 redux-toolkit 登录时重定向页面
问题描述
我正在使用 react-router-dom v5.2。
登录后,我希望我的页面重定向到/home
from /
。登录表单位于/
。
当我尝试在没有任何异步功能的情况下执行身份验证时(即,将用户名和密码与反应中的硬编码值进行比较),一切正常。
但是当我使用 express 和 mongo 执行身份验证时,登录时的重定向停止工作。如果我再次登录,则会发生重定向。受保护的路由仍然有效(如果用户未登录,则重定向到登录页面)。
这是我在 express + mongo 中使用 do auth 的问题的一个小演示,即。异步还原。这没有按预期工作。https://youtu.be/Zxm5GOYymZQ
这是我使用硬编码的用户名和密码(均为“测试”)进行身份验证的应用程序的链接。这里没有异步。这按预期工作。用户名和密码都是“测试”。https://poke-zoo.herokuapp.com/
这是App.js
:
const ProtectedRoute = ({ component: Component, ...rest }) => {
const authState = useSelector(selectorAuth)
// const location = useLocation()
return (
<Route
{...rest}
render={props => {
if (authState.isUserLoggedIn) {
return <Component {...props} />
} else {
return (
<Redirect
to={{
pathname: "/",
state: {
from: props.location,
},
}}
/>
)
}
}}
/>
)
}
const App = () => {
return (
<Router>
<div tw="flex flex-col bg-green-100 min-h-screen">
<Navbar />
<Switch>
<Route exact path="/" component={Landing} />
<ProtectedRoute path="/home" component={Home} />
<ProtectedRoute path="/explore" component={Explore} />
<Route path="*" component={() => "404 Not found."} />
</Switch>
</div>
</Router>
)
}
这是ModalLogin.js
.
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 (
<div tw="flex flex-col text-center h-full w-64 bg-gray-200 text-gray-900 rounded-lg shadow-lg p-2 md:p-4 lg:p-6">
<div tw="flex flex-row justify-between">
<p tw="text-lg">Login</p>
<button tw="text-sm" onClick={() => setLoginModalBool(!loginModalBool)}>
close
</button>
</div>
<div tw="flex flex-col justify-around my-1">
<form onSubmit={attemptLogin} tw="">
<input
tw="my-1"
value={username}
onChange={e => setUsername(e.target.value)}
placeholder="username"
/>
<input
tw="my-1"
value={password}
onChange={e => setPassword(e.target.value)}
type="password"
placeholder="password"
/>
<button
type="submit"
tw="my-1 p-1 rounded bg-gray-800 text-gray-100 hover:bg-gray-900"
>
log in
</button>
</form>
</div>
</div>
)
}
这是authSlice.js
.
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
我是否错误地将 react-router 与 redux-toolkit 一起使用?
解决方案
您的代码在登录后未定义重定向逻辑。你可以通过两种方式做到这一点。
第一:如果您希望您的路由在身份验证时重定向,您可以定义另一个重定向包装器进行身份验证。
const AuthRoute = ({ component: Component, ...rest }) => {
const authState = useSelector(selectorAuth)
const location = useLocation()
return (
<Route
{...rest}
render={props => {
if (!authState.isUserLoggedIn) {
return <Component {...props} />
} else {
return (
<Redirect
to={{
pathname: "/home",
state: {
from: location,
},
}}
/>
)
}
}}
/>
)
}
const App = () => {
return (
<Router>
<div tw="flex flex-col bg-green-100 min-h-screen">
<Navbar />
<Switch>
// It is for login users to redirect to home page
<AuthRoute exact path="/" component={Landing} />
<ProtectedRoute path="/home" component={Home} />
<ProtectedRoute path="/explore" component={Explore} />
<Route path="*" component={() => "404 Not found."} />
</Switch>
</div>
</Router>
)
}
第二:另一种方法可以用 history.push() 或 history.replace() 强制处理:
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 (
<Switch>
<Route exact path="/" component={Landing} />
<ProtectedRoute path="/home" component={Home} />
<ProtectedRoute path="/explore" component={Explore} />
<Route path="*" component={() => "404 Not found."} />
</Switch>
);
};
const App = () => {
return (
<Router>
<div tw="flex flex-col bg-green-100 min-h-screen">
<Navbar />
<Layout />
</div>
</Router>
);
};
为什么你的代码不起作用?看看下面的代码:
<Route exact path="/" component={Landing} />
<ProtectedRoute path="/home" component={Home} />
<ProtectedRoute path="/explore" component={Explore} />
<Route path="*" component={() => "404 Not found."} />
它能做什么? 它会检查您的浏览器路径并检查它是否与从上到下的给定路由规则匹配。如果 Route 路径匹配,那么它会渲染组件,否则它会继续向下访问每个 Route,直到它与您的 404 匹配。
回到你的情况;当您登录时,您没有离开“/”路径。因为没有实现离开“/”路径的逻辑。因此,即使它已通过身份验证,它也会再次与登录页面匹配。它与路由路径(登陆页面)匹配并停留在那里。它不会继续并在 ProtectedRoute 上尝试您的逻辑。
推荐阅读
- uwp - 如何在 CanvasGeometry 上添加效果
- angular - Angular 6 - 如何在 IF 条件下更改其模板中的组件值
- file-io - 在 Julia 1.0.0 中将大数字输出保存到本地文件
- html - 悬停一个元素以更改另一个不是子元素或兄弟元素的元素
- javascript - 如何使用 JavaScript 制作分秒的倒数计时器?
- node.js - 如何使用 NodeJS SDK for IBM Cloud Object Storage 生成预签名链接?
- delphi - Delphi 10.2 中未设置编译器指令
- javascript - 为什么以下 JS 代码不会在浏览器中终止?
- react-native - 如何在自定义 react-native TextInput 中实现焦点/模糊响应
- javascript - 样式列表项 onMouseOver - React.js