传奇异步请求后如何设置状态

how to setstate after saga async request

我在我的项目中使用 redux-saga。 我以前用过 redux-thunk,所以我不能设置一些异步请求的结束。喜欢

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

因为thunk return的承诺,我可以使用'then'。 但我不能用 saga 做到这一点,因为 saga 没有 return 承诺。 所以我在 componentWillReceiveProps 中通过检查标志道具(如 REQUEST_SUCCESS、REQUEST_WAITING...)已更改。 我认为这不是解决这个问题的好方法。

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

But i can't do this with saga, because saga doesn't return promise

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

使用 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 进程管理器。

您发出的每个 api 调用都作为异步请求处理,但在 saga 中使用生成器函数处理。

因此,在成功调用 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 State 并通过 mapStateToProps 从 props 获取

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

你可以这样做。从组件 props 调用 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)
  ]);
}

In component call call setState method in the function you pass to saga as param

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



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

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

我的解决方案是将调度包装在一个 promise 中,并在 saga 函数中调用 resolve 和 reject...

我创建了一个挂钩来包装调度。你可以在这里看到我的例子: https://github.com/ricardocanelas/redux-saga-promise-example

希望对大家有所帮助。