我正在尝试使用React Router 4 + Redux实现一个简单的授权流程。
authorization
(商店中的布尔值)为false
,则任何路由都应重定向到登录页面。 authorization
为true
,则任何路线都应呈现该路线。 <CheckAuth>
(即react-redux connect),用于访问商店中的authorization
布尔值。<CheckAuth>
接受两个组件<Protected>
和<LoginPage>
,并根据布尔值决定一个或另一个。<CheckAuth>
内,根据<Route>
,呈现了<Redirect>
所请求的组件或authorization
。<LoginPage>
中的表单会调度LOGIN
操作,将authorization
布尔值设置为true。<Protected>
中的表单将调度LOGOUT
操作,将authorization
布尔值设置为false。 (此表单应与<Protected>
分开,但我将它们放在一起以保持示例简单。)我遇到的问题是,当商店发生变化时,组件似乎没有更新。对页面进行硬刷新会更新视图,但它也会消除商店,并且只会出错。
我可能在某处做了一些错误的假设。如果有人可以提供帮助,我将不胜感激!
我创建了一个简化版的代码,如下所示,可以粘贴到create-react-app
App.js
文件中。下面是一个package.json
文件,可以启动并运行它。 (在我正在使用的版本中,auth会持久化为cookie,因此刷新不会清除身份验证。)
除了可能提供的任何解决方案之外,我还喜欢调试react应用程序的任何提示,尤其是路由器。
App.js:
// import Libs
import React, { Component } from "react"
import { BrowserRouter as Router, Route, Redirect } from "react-router-dom"
import { createStore, applyMiddleware } from "redux"
import { Provider, connect } from "react-redux"
import { createLogger } from "redux-logger"
const loggerMiddleware = createLogger()
// create Store/Reducer
const store = createStore((state = { authenticated: false }, action) => {
switch (action.type) {
case "LOGIN":
return {
authenticated: true
}
case "LOGOUT":
return {
authenticated: false
}
default:
return state
}
}, applyMiddleware(loggerMiddleware))
// <CheckAuth> component
const CheckAuth = ({ authenticated, location, LoginPage, Protected }) => {
const { pathname } = location
if (authenticated) {
if (pathname === "/login") {
return <Redirect to="/" />
}
return <Route path={pathname} component={Protected} />
}
if (pathname === "/login") {
return <Route path="/login" component={LoginPage} />
}
return <Redirect to="login" />
}
const mapStateToProps = state => ({
authenticated: state.authenticated
})
const CheckAuthContainer = connect(mapStateToProps)(CheckAuth)
// Log in and out Actions
const authenticate = () => ({
type: "LOGIN"
})
const removeAuth = () => ({
type: "LOGOUT"
})
// <Login> component
const Login = ({ dispatch }) => {
const login = e => {
e.preventDefault()
dispatch(authenticate())
}
return (
<form onSubmit={login}>
<button type="Submit">Login</button>
</form>
)
}
// <LoginPage> component
const LoginContainer = connect()(Login)
const ProtectedPage = ({ dispatch }) => {
const logout = e => {
e.preventDefault()
dispatch(removeAuth())
}
return (
<div>
<h1>Protected</h1>
<form onSubmit={logout}>
<button type="Submit">Logout</button>
</form>
</div>
)
}
const ProtectedPageContainer = connect()(ProtectedPage)
class App extends Component {
render() {
return (
<Provider store={store}>
<Router>
<CheckAuthContainer
LoginPage={LoginContainer}
Protected={ProtectedPageContainer}
location={location}
/>
</Router>
</Provider>
)
}
}
export default App
的package.json:
{
"name": "test-redux-router-redirect",
"version": "0.1.0",
"private": true,
"dependencies": {
"react": "^15.5.4",
"react-dom": "^15.5.4",
"react-redux": "^5.0.4",
"react-router-dom": "^4.1.1",
"redux": "^3.6.0",
"redux-logger": "^3.0.1",
"redux-thunk": "^2.2.0"
},
"devDependencies": {
"react-scripts": "0.9.5"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
}
}
答案 0 :(得分:4)
我明白了。
The React Router documentation's section on Redux integration实际上直接解决了这个问题,但不知怎的,我误解了如何应用它。
将<CheckAuthContainer>
组件传递到withRouter
解决了我的问题。所以第45行看起来像这样:
const CheckAuthContainer = withRouter(connect(mapStateToProps)(CheckAuth))
我还没有在我正在开发的真实应用程序中试过这个。希望它也能在那里工作!