我有一个这样定义的组件。fetchBrands
是一个redux动作
class Brands extends Component {
componentWillMount() {
this.props.fetchBrands();
}
render() {
return (
// jsx omitted for brevity
);
}
}
function mapStateToProps(state) {
return { brands: state.brands.brands }
}
export default connect(mapStateToProps, { fetchBrands: fetchBrands })(Brands);
这个组件被包装在一个高阶组件中,看起来像这样:
export default function(ComposedComponent) {
class Authentication extends Component {
// kind if like dependency injection
static contextTypes = {
router: React.PropTypes.object
}
componentWillMount() {
if (!this.props.authenticated) {
this.context.router.push('/');
}
}
componentWillUpdate(nextProps) {
if (!nextProps.authenticated) {
this.context.router.push('/');
}
}
render() {
return <ComposedComponent {...this.props} />
}
}
function mapStateToProps(state) {
return { authenticated: state.auth.authenticated };
}
return connect(mapStateToProps)(Authentication);
}
然后,在我的路由器配置中,我做了以下操作:
<Route path="brands" component={requireAuth(Brands)} />
如果本地存储中不存在验证令牌,则重定向到公共页面。然而,fetchBrands
动作仍然被调用,这是触发一个ajax请求。由于缺乏验证令牌,服务器拒绝了它,但我甚至不希望进行调用。
export function fetchBrands() {
return function(dispatch) {
// ajax request here
}
}
我可以用if/else
检查包装ajax请求,但考虑到我需要这样做的所有操作函数,这不是很DRY。我怎么能实现一些DRY来防止调用,如果auth在浏览器级别失败?
您应该为此编写一个中间件。http://redux.js.org/docs/advanced/Middleware.html
既然你正在使用axios,我建议你使用https://github.com/svrcekmichal/redux-axios-middleware
那么你可以使用像
这样的中间件const tokenMiddleware = store => next => action => {
if (action.payload && action.payload.request && action.payload.request.secure) {
const { auth: { isAuthenticated } } = store.getState()
const secure = action.payload.request.secure
if (!isAuthenticated && secure) {
history.push({ pathname: 'login', query: { next: history.getCurrentLocation().pathname } })
return Promise.reject(next({ type: 'LOGIN_ERROR', ...omit(action, 'payload') }))
}
}
return next(action)
}
action.payload.request。secure是我用来指示请求需要身份验证的自定义道具。
在这种情况下,我也使用历史重定向从react-router,但你可以处理这个调度另一个操作(store。调度({whatever}))并根据需要作出反应