Reactjs 在启动操作调用的视图中处理Redux Saga结果
我是Redux传奇的新手,来自Redux Thunk。在某些情况下,我需要从调用动作的视图中了解API调用是失败还是成功。有了Redux Thunk,我会做如下的事情 我的组件和动作创建者如下所示: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
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调用的结果(nopromise.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实现这一点,而不创建创建用户和项目操作?