Reactjs 在启动操作调用的视图中处理Redux Saga结果

Reactjs 在启动操作调用的视图中处理Redux Saga结果,reactjs,promise,redux,react-redux,redux-saga,Reactjs,Promise,Redux,React Redux,Redux Saga,我是Redux传奇的新手,来自Redux Thunk。在某些情况下,我需要从调用动作的视图中了解API调用是失败还是成功。有了Redux Thunk,我会做如下的事情 我的组件和动作创建者如下所示: class MyComponent extends Component { componentDidMount() { this.props.actions.fetchItems() .then(result => { if (result.status

我是Redux传奇的新手,来自Redux Thunk。在某些情况下,我需要从调用动作的视图中了解API调用是失败还是成功。有了Redux Thunk,我会做如下的事情

我的组件和动作创建者如下所示:

class MyComponent extends Component {

  componentDidMount() {
    this.props.actions.fetchItems()
    .then(result => {
        if (result.status === 'OK') {
            console.log('Request succeeded, take particular action in this view')
        }
        else {
            console.log('Request failed, take other action in this view')
        }
    })
  }

  render() {
    return (
        <div>My view</div>
    )
  }
}


const mapStateToProps = (state, ownProps) => {
    return {
        items: state.items,
    }
}

const mapDispatchToProps = dispatch => {
    return {
        actions: bindActionCreators({
            ...actions,
        }, dispatch),
    }
}


export default connect(
    mapStateToProps,
    mapDispatchToProps,
)(MyComponent)



import * as t from './actionTypes'
import {CALL_API} from '../api'

const xhrGetItems = (params) => (dispatch, getState) => {
    const action = {
        [CALL_API]: {
            type: t.XHR_ITEMS_FETCH,
            endpoint: `http://www.example.com/myendpoint`,
            method: 'get',
        }
    }
    return dispatch(action)
}
function* watchListItemsStart() {
  yield takeLatest(LIST_ITEMS_START, listItemsStartFlow)
}

function* listItemsStartFlow() {
  try {
    const result = yield call(api.getItems)

    if (result.status === 'OK') {
      yield put(LIST_ITEMS_SUCCEEDED, items)
    } else {
      throw new Error(result.error)
    }
  } catch (error) {
    yield put(LIST_ITEMS_FAILED, error)
  }
}
类MyComponent扩展组件{
componentDidMount(){
this.props.actions.fetchItems()
。然后(结果=>{
如果(result.status==='OK'){
console.log('请求成功,在此视图中执行特定操作')
}
否则{
console.log('请求失败,在此视图中执行其他操作')
}
})
}
render(){
返回(
我的看法
)
}
}
const mapStateToProps=(state,ownProps)=>{
返回{
项目:state.items,
}
}
const mapDispatchToProps=调度=>{
返回{
操作:bindActionCreators({
…行动,
},派遣),
}
}
导出默认连接(
MapStateTops,
mapDispatchToProps,
)(MyComponent)
从“/actionTypes”导入*作为t
从“../API”导入{CALL_API}
const xhrGetItems=(参数)=>(分派,getState)=>{
常量动作={
[调用API]:{
类型:t.XHR\u ITEMS\u FETCH,
终点:`http://www.example.com/myendpoint`,
方法:“get”,
}
}
退货派送(行动)
}
我的API中间件使用
CALL\u API
属性捕获所有操作,使用ajax库进行适当的调用,然后返回已实现的承诺。我的reducer设置为处理api调用的每个可能状态(成功、失败、挂起)。在这期间,我仍然可以在我的视图中查看调用的结果

所以我的问题是,如何通过Redux传奇实现这一点?现在我的saga api中间件正在做它应该做的一切,但是当我在视图中调用
fetchItems()
时,结果是一个普通的JS对象,所以我无法检查它是否成功


我也有可能完全错了。非常感谢您的建议。

redux和redux传奇的一个常见模式是为一个API调用创建3个操作。在您的情况下,我将创建:

  • 列出\u项目\u开始
  • 列出\u个项目\u成功
  • 列出项目失败
你的传奇故事看起来像这样:

class MyComponent extends Component {

  componentDidMount() {
    this.props.actions.fetchItems()
    .then(result => {
        if (result.status === 'OK') {
            console.log('Request succeeded, take particular action in this view')
        }
        else {
            console.log('Request failed, take other action in this view')
        }
    })
  }

  render() {
    return (
        <div>My view</div>
    )
  }
}


const mapStateToProps = (state, ownProps) => {
    return {
        items: state.items,
    }
}

const mapDispatchToProps = dispatch => {
    return {
        actions: bindActionCreators({
            ...actions,
        }, dispatch),
    }
}


export default connect(
    mapStateToProps,
    mapDispatchToProps,
)(MyComponent)



import * as t from './actionTypes'
import {CALL_API} from '../api'

const xhrGetItems = (params) => (dispatch, getState) => {
    const action = {
        [CALL_API]: {
            type: t.XHR_ITEMS_FETCH,
            endpoint: `http://www.example.com/myendpoint`,
            method: 'get',
        }
    }
    return dispatch(action)
}
function* watchListItemsStart() {
  yield takeLatest(LIST_ITEMS_START, listItemsStartFlow)
}

function* listItemsStartFlow() {
  try {
    const result = yield call(api.getItems)

    if (result.status === 'OK') {
      yield put(LIST_ITEMS_SUCCEEDED, items)
    } else {
      throw new Error(result.error)
    }
  } catch (error) {
    yield put(LIST_ITEMS_FAILED, error)
  }
}
这些传奇清晰地消除了API的副作用。减速器可以专注于状态管理:

switch (action.type) {
  case LIST_ITEMS_START:
    return {
      ...state,
      isLoading: true,
      error: null,
      items: [],
    }
  case LIST_ITEMS_SUCCEEDED:
    return {
      ...state,
      isLoading: false,
      items: action.payload.items,
    }
  case LIST_ITEMS_FAILED:
    return {
      ...state,
      isLoading: false,
      error: action.payload.error.getMessage(),
    }
}
现在,您的商店中有了所需的一切,您可以在组件中选择和响应这些内容

class MyComponent extends Component {
  componentDidMount() {
    this.props.fetchItems()
  }

  render() {
    const { isLoading, items, error } = this.props

    // Here you can react to the different states.

    return (
      <div>My view</div>
    )
  }
}

connect(state => ({
  isLoading: itemsSelectors.isLoading(state),
  items: itemsSelectors.getItems(state),
  error: itemsSelectors.getError(state),
}), {
  fetchItems: actions.fetchItems
})(MyComponent)
类MyComponent扩展组件{
componentDidMount(){
this.props.fetchItems()
}
render(){
const{isLoading,items,error}=this.props
//在这里你可以对不同的状态做出反应。
返回(
我的看法
)
}
}
连接(状态=>({
isLoading:项目选择器。isLoading(状态),
items:itemsSelectors.getItems(状态),
错误:itemsSelectors.getError(状态),
}), {
fetchItems:actions.fetchItems
})(MyComponent)
这里重要的一点是,您的组件变得非常愚蠢。它只获取道具,不处理API调用的结果(no
promise.then
here)


我希望这个答案能对你有所帮助。

谢谢你的回答@Alex。你所描述的基本上就是我设置的。我的问题是如何让组件保持智能。这方面的一个用例是:用户通过api调用发布数据。请求成功后,将用户重定向到不同的页面/组件(例如,使用react router
browserHistory.push(“/myPath”)
)。通常我会在组件内部调用这个重定向。有没有更好的方法可以做到这一点,我没有考虑?根据您的描述和我目前的设置,我需要通过签入
componentWillReceiveProps(nextrops)
this.props.isLoading&!nextProps.isLoading
,然后根据nextProps.error采取适当的措施(例如,成功时导航到新组件或出现错误时显示错误消息)。对于一些简单的事情来说,这似乎是一个很长的解决方法。你能评论一下这个特定用例的最佳实践吗?你所有的副作用,如路由、api调用等,都应该进入这个故事。因此,在我检查
if(result.status=='OK')
的故事中,您可以放置路由器逻辑。如果这些组件都是可用的,你的生活会变得更轻松!不聪明,但再次感谢@Alex。你知道有哪些真实世界的项目/例子是可以公开查看的吗?非常好,但不处理任何post/put/patch/delete操作。任何建议都将不胜感激!不保证。然后。。。。这是我的问题,假设我有一个干净的redux saga设置,允许创建用户,然后我想使用返回的用户id来链接一个操作,比如说创建项目,我如何使用redux saga实现这一点,而不创建创建用户和项目操作?