防止来自redux操作的未处理的ajax请求

时间:2016-08-29 20:10:19

标签: authentication reactjs redux dry react-redux

我有一个像这样定义的组件。 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到如果auth在浏览器级别失败,则阻止调用?

1 个答案:

答案 0 :(得分:0)

你应该为此编写一个中间件。 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-routing中的历史重定向,但是你可以处理这个以分发另一个动作(store.dispatch({whatever}))并根据需要做出反应