如何在saga异步请求后设置状态

时间:2017-11-22 04:48:02

标签: reactjs redux redux-thunk redux-saga

我在我的项目中使用了redux-saga。 之前我使用过redux-thunk,所以我无法设置某些异步请求的StateState。像

this.props.thunkAsync()
  .then(){
    this.setState({ '' });
  }

由于thunk返回promise,我可以使用'then'。 但我无法用传奇做到这一点,因为传奇并没有回报承诺。 所以我在componentWillReceiveProps中通过检查标志道具(如REQUEST_SUCCESS,REQUEST_WAITING ......)来改变它。 我认为这不是解决这个问题的好方法。

那么..我的问题是当异步请求在redux-saga中结束时,我该如何做一些工作!

4 个答案:

答案 0 :(得分:4)

  

但是我无法用传奇做到这一点,因为传奇并没有回报承诺

Redux-sagathunk略有不同,因为它是流程管理器,而不是简单的中间件:thunk仅对已触发的操作执行反应,但saga有自己的&# 34;处理" (正式回调刻度域)并且可以通过效果操作。

使用redux-saga执行异步操作的常用方法是将原始操作拆分为ACTION_REQUESTACTION_SUCCESSACTION_FAILURE变体。然后reducer只接受SUCCESS / FAILURE动作,也许接受optimistic updates的REQUEST。

在这种情况下,您的saga流程可能如下

function* actionNameSaga(action) {
    try {    
        const info = yield call(fetch, { params: action.params }
        yield put('ACTION_NAME_SUCCESS', info)
    } catch(err) {
        yield put('ACTION_NAME_FAILURE', err)
    }

function* rootSaga() {
    yield takeEvery('ACTION_NAME', actionNameSaga)
}

请记住,yield操作本身不是关于承诺等待 - 它只是委托等待saga进程管理器的异步。

答案 1 :(得分:2)

您进行的每个api调用都将作为异步请求处理,但会使用传奇中的生成器函数进行处理。

因此,在成功调用api之后,您可以执行以下可能的操作。

  1. 进行另一个api调用
function* onLogin(action) {
  try {
    const { userName, password } = action;
    const response = yield call(LoginService.login, userName, password);
    yield put(LoginService.loginSuccess(response.user.id));
    const branchDetails = yield call(ProfileService.fetchBranchDetails, response.user.user_type_id);
    yield put(ProfileActions.fetchBranchDetailsSuccess(branchDetails));
  } catch (error) {
    yield put(ProfileActions.fetchUserDetailsError(error));
  }
}
  1. API成功后传递回叫

    onLoginClick() {
      const { userName, password } = this.state;
      this.props.login(userName, password, this.onLoginSuccess);
    }
    
    onLoginSuccess(userDetails) {
      this.setState({ userDetails });
    }
    
    function *onLogin(action) {
      try {
         const { userName, password, onLoginSuccess } = action;
         const response = yield call(LoginService.login, userName, password);
         if (onLoginSuccess) {
             onLoginSuccess(response);
         }
    
         yield put(LoginService.loginSuccess(response.user.id));
         const branchDetails = yield call(ProfileService.fetchBranchDetails, 
         response.user.user_type_id);
         yield put(ProfileActions.fetchBranchDetailsSuccess(branchDetails));
     } catch (error) {
         yield put(ProfileActions.fetchUserDetailsError(error));
     }
    

    }

  2. 更新Reducer状态并通过mapStateToProps从道具获取

    yield put(LoginService.loginSuccess(response.user.id));        
    @connect(
        state => ({
            usedDetails: state.user.get('usedDetails'),
        })
    )
    static getDerivedStateFromProps(nextProps, prevState) {
        const { usedDetails } = nextProps;
        return {
            usedDetails
        }
    }
    

答案 2 :(得分:0)

您可以这样做。在组件属性中,您可以调用saga方法,并在成功或失败后传递要执行的功能,如下所示

export function* login({ payload }) {
  const url = 'localhost://login.json';

 try {
    const response = yield call(App_Service, { url, method: 'GET' });
 if (response.result === 'ok' && response.data.body) {
    yield put(fetchDataActionCreators.getLoginSuccess(response.data.body));
    //function passed as param from component, pass true if success
    payload.callback(true);
  }


 } catch (e) {
        //function passed as param from component, pass false if failure
    payload.callback(false);
    console.log(e);
  }
}


export function* watchLogin() {
  while (true) {
    const action = yield take(LOGIN);
    yield* login(action);
  }
}



export default function* () {
  yield all([
    fork(watchLogin)
  ]);
}
  

在函数中的组件调用调用setState方法中,以参数形式传递给saga

login() {
    // store
    this.props.getServiceDetails({
       callback:(success) => this.onLoginSuccess(success)
    })
  }



onLoginSuccess = (success) => {
    this.setState({
       login:success
    })
    alert('login '+success)
  }

答案 3 :(得分:0)

我也遇到了同样的问题...

我的解决方案是将调度包裹在一个Promise中,并在saga函数中调用resolve和拒绝...

我创建了一个用于包装分发的钩子。您可以在这里看到我的示例: https://github.com/ricardocanelas/redux-saga-promise-example

我希望可以对某人有所帮助。