【问题标题】:Handling Redux Saga result in view from which action call originates处理 Redux Saga 结果的视图,从哪个动作调用发起
【发布时间】:2017-10-14 22:40:54
【问题描述】:

我是 Redux Saga 的新手,来自 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)
}

我的 API 中间件使用 CALL_API 属性捕获所有操作,使用 ajax 库进行适当的调用,然后返回一个已履行的承诺。我的 reducer 设置为处理 api 调用的每种可能状态(成功、失败、挂起)。一直以来,我仍然可以在我的视图中检查调用的结果。

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

我也可能完全错了。非常感谢任何建议。

【问题讨论】:

    标签: reactjs promise redux react-redux redux-saga


    【解决方案1】:

    redux 和 redux-saga 的一个常见模式是为一个 API 调用创建 3 个操作。在你的情况下,我会创建:

    • LIST_ITEMS_START
    • LIST_ITEMS_SUCCEEDED
    • LIST_ITEMS_FAILED

    你的传奇应该是这样的:

    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)
      }
    }
    

    sagas 已经清晰地抽象出 API 的副作用。 reducer 可以专注于状态管理:

    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)
    

    这里很重要的一点是,您的组件变得非常愚蠢。它只是获取道具,不处理 API 调用的结果(这里没有 promise.then)。

    希望这个回答对你有帮助。

    【讨论】:

    • 感谢您的回答@Alex。你描述的基本上就是我设置的。我的问题是关于如何让组件保持智能。一个用例是:用户通过 api 调用发布数据。请求成功后,将用户重定向到不同的页面/组件(例如,使用 react-router browserHistory.push('/myPath'))。通常我会在组件内部调用这个重定向。有没有我没有考虑过的更好的方法来做到这一点?
    • 根据您描述的内容和我目前设置的内容,我需要通过签入componentWillReceiveProps(nextProps) this.props.isLoading &amp;&amp; !nextProps.isLoading 来执行此操作,然后根据nextProps.error 采取适当的措施(例如导航到新组件成功或显示错误消息)。对于简单的事情,这似乎是一个漫长的解决方法。你能评论一下这个特定用例的最佳实践吗?
    • 你所有的副作用,如路由、api 调用等都应该进入 saga。因此,在我检查if (result.status === 'OK') 的传奇中,您可以放置​​路由器逻辑。如果组件不是聪明而是愚蠢的,你会让你的生活更轻松
    • 再次感谢@Alex。您是否知道任何可以公开查看的真实世界项目/示例? The real-world example from redux-saga docs 非常好,但不处理任何 post/put/patch/delete 操作。任何建议表示赞赏!
    • no promise.then.... 这是我的问题,假设我有一个干净的 redux-saga 设置允许创建用户,然后我想使用返回的用户 ID 来链接操作,假设创建项目,我如何使用 redux-saga 做到这一点,而不创建创建用户和项目操作?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-08
    • 2021-12-03
    • 2018-10-17
    • 2018-12-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多