React-Redux如何根据成功条件调用新的调度

时间:2017-04-30 08:18:39

标签: javascript reactjs redux react-redux

我已经有一段时间了。看着this问题,但它不是我想要的。

简而言之......我将const表达式=连接到另一个函数,该函数在一个单独的文件中对一个文件进行API调用,但是在同一个文件夹中 - (它叫做reducer.js但是有动作)以及在这个阶段)。如果成功,它将收到一个令牌,并将其保存在本地存储中。这很好。

在这里。

import { fetch, addTask } from 'domain-task'
import { saveJwt, clearJwt } from '../auth/jwt'
import { handleErrors } from '../utils/http'

const REQUEST_LOGIN_TOKEN = 'REQUEST_LOGIN_TOKEN'
const RECEIVE_LOGIN_TOKEN = 'RECEIVE_LOGIN_TOKEN'
const ERROR_LOGIN_TOKEN = 'ERROR_LOGIN_TOKEN'
const REQUEST_USER = 'REQUEST_USER'
const RECEIVE_USER = 'RECEIVE_USER'
const ERROR_USER = 'ERROR_USER'

// ******************* action
export const requestLoginToken = (username, password) =>
  (dispatch, getState) => {
    dispatch({ type: REQUEST_LOGIN_TOKEN, payload: username })

    const payload = {
      userName: username,
      password: password,
    }

    const task = fetch('/api/jwt', {
      method: 'POST',
      body: JSON.stringify(payload),
      headers: {
        'Content-Type': 'application/json;charset=UTF-8'
      },
    })
      .then(handleErrors)
      .then(response => response.json())
      .then(data => {
        dispatch({ type: RECEIVE_LOGIN_TOKEN, payload: data })
        saveJwt(data)
      })
      .catch(error => {
        clearJwt()
        dispatch({ type: ERROR_LOGIN_TOKEN, payload: error.message })
      })
    addTask(task)
    return task
  }



import React, { Component, PropTypes } from 'react'
import { connect } from 'react-redux'
import Login from './Login'
import { requestLoginToken } from './reducer'

class LoginContainer extends Component {
  static contextTypes = {
    router: PropTypes.object.isRequired
  }

  componentWillReceiveProps(nextProps) {
    if (nextProps.isAuthorised) {
      this.context.router.push('/')
    }
  }

  submit = (values) => {
    console.log('got values!', values)
    this.props.requestLoginToken(values.username, values.password)
  }

  render() {
    return (
      <Login onSubmit={this.submit} />
    )
  }
}

const mapStateToProps = (state) => ({
  isAuthorised: state.login.isAuthorised,
})
const mapDispatchToProps = (dispatch) => ({
  requestLoginToken: (username, password) => dispatch(requestLoginToken(username, password)),
  //requestSelectData: (values = {}) => dispatch(requestSelectData(values = {})),
})
export default connect(mapStateToProps, mapDispatchToProps)(LoginContainer)

在loginContainer(上图)中,输入“userName”和“password”并单击提交按钮后,将调用表达式“requestLoginToken”。

我的问题

我想基于上面的表达式“requestLoginToken”获取大量数据,成功地将JWT令牌保存到本地存储中。它现在使用正确的用户名和密码成功完成此操作。

我知道我不能使用“.then”在表达式“requestLoginToken”中进行另一次调用,因为它特别需要检索然后首先保存一个令牌 - 我必须等到它完成才知道我是否有一个令牌。我需要运行第二个表达式,只有在此承诺成功时才会运行,即通过条件语句。 “如果(JWT)等”

1)有人可以告诉我在哪里以及如何添加此条件语句。我在提交的Logincontainer中思考它? ..我会如何构建条件?

2)我在何处以及如何添加const =函数来检索数据,例如,如果我将它放在另一个单独的文件中,我是否仍然需要在loginContainer等的mapDispatchToProps中注册它

修改

接受Nate Kimball的回答并使用它。决定将它拆分为自己的“const”,称为“selectData”,我打算在“saveJwt(data)”行下面调用它。

但是我发现我现在收到错误:

  

意外令牌,预期

它位于下面代码块的最后一行..(右大括号下面有红色)检查它是否为sytax但是为什么不能锻炼。

我认为这种方法是正确的。

const selectData = () => {
  dispatch({ type: REQUEST_SELECT_DATA })

  const token = jwt.access_token
  const headers = new Headers({
    'Authorization': `Bearer ${token}`
  })
  const selectData = fetch('/api/SelectData/SelectData', {
    method: 'GET',
    headers,
  })
    .then(handleErrors)
    .then(response => response.json())
    .then(data => {
      dispatch({ type: RECEIVE_SELECT_DATA, payload: data })
        .catch(error => {
          clearJwt()
          dispatch({ type: ERROR_SELECT_DATA, payload: error.message })
        })
    }
}

3 个答案:

答案 0 :(得分:1)

您可以在其他动作创建者中使用controller: ()=>{ let vm = this; $onInit(){ vm.entries = new Array(vm.value); onsole.log(vm.entries); } }

requestLoginToken

作为替代方案,您可以将获得的令牌保存到商店,然后让另一个组件侦听令牌的更改,并在令牌更改时发送另一个操作。

function loginAndFetch() {
    return function(dispatch, getState) {
      dispatch(requestLoginToken()).then(token => {
          return fetch(...)  // use token here
      })
    }
}

连接容器并将存储的令牌映射到class Container extends Component { componentDidUpdate(prevProps, prevState) { if (this.props.token != prevProps.token) { dispatch(fetchSignificantAmountOfData()) } } }

答案 1 :(得分:1)

我没有看到任何理由说明您在成功通话后无法在动作中嵌套第二次抓取:

export const requestLoginToken = (username, password) =>
  (dispatch, getState) => {
    dispatch({ type: REQUEST_LOGIN_TOKEN, payload: username })

    const payload = {
      userName: username,
      password: password,
    }

    const task = fetch('/api/jwt', {
      method: 'POST',
      body: JSON.stringify(payload),
      headers: {
        'Content-Type': 'application/json;charset=UTF-8'
      },
    })
      .then(handleErrors)
      .then(response => response.json())
      .then(data => {
        dispatch({ type: RECEIVE_LOGIN_TOKEN, payload: data })
        saveJwt(data)
        // Since this is where you receive your login token,
        // You can dispatch an action to acknowledge you're fetching:
        dispatch({ type: SECOND_DATA_FETCHING })
        // This is also where you would make your next call:
        fetch('/api/etc', { ...config })
        .then(response => {
            // You can use your reducer to both inform a successful call &
            // store the received data
            dispatch({ type: SECOND_DATA_SUCCESS, payload: response.data })
        })
        .catch(error => {
            // Let your app know the call was unsuccessful:
            dispatch({ type: SECOND_DATA_FAILED, payload: error.message })
        })

        // Note: if you don't like the nested ugliness, you could optionally
        // put this entire nested fetch chain into a separate action and just 
        // dispatch that when you get your token.
      })
      .catch(error => {
        clearJwt()
        dispatch({ type: ERROR_LOGIN_TOKEN, payload: error.message })
      })
    addTask(task)
    return task
  }

此时,您需要做的就是更新组件中的mapStateToProps函数,以接收数据和/或第二层提取数据的状态:

// Make sure you have a default status for that second data
// just in case your token call fails. 
const mapStateToProps = (state) => ({
  isAuthorised: state.login.isAuthorised,
  secondData: state.login.secondData,
  secondDataStatus: state.login.secondDataStatus
})

答案 2 :(得分:0)

您可以编写自定义中间件来解决此问题,如下所示:

https://github.com/erikras/react-redux-universal-hot-example/blob/master/src/redux/middleware/clientMiddleware.js

然后,你可以使用这样的动作:

export function myAction() {
  return {
    types: [LOAD, SUCESS, FAIL],
    promise: (client) => client.get('/some_api')
  };
}

中间件首先调度LOAD减速器,然后如果promise被解析,则调用SUCESS;否则,将调用FAIL。