【问题标题】:how to setstate after saga async request如何在 saga 异步请求后设置状态
【发布时间】:2018-05-05 17:41:53
【问题描述】:

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

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

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

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

【问题讨论】:

  • 你可以把 react 的 state 设置为 redux state,这样你就可以在 saga 本身中设置 state,并在这个组件中使用 redux state。
  • 我想到了..谢谢!但是如果我想调用一些只能在本地工作的函数呢?
  • 如果你使用 redux 来管理状态,那么你可以触发一个动作并在你的 reducer 中处理它来设置状态。
  • @godsenal 如果可以的话,您很可能应该将这些功能移至 saga。
  • @AnandS 谢谢!但是如果我想在异步请求结束后更改内联样式怎么办?我应该将此样式对象(或某些局部变量)移动到我的 redux 状态吗?

标签: reactjs redux redux-thunk redux-saga


【解决方案1】:

但我不能用 saga 做这个,因为 saga 不返回承诺

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

使用redux-saga 执行异步操作的通常方法是将原始操作拆分为ACTION_REQUESTACTION_SUCCESSACTION_FAILURE 变体。然后 reducer 只接受 SUCCESS/FAILURE 操作,并且可能对optimistic updates 进行请求。

在这种情况下,您的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 流程管理器。

【讨论】:

    【解决方案2】:

    您进行的每个 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
          }
      }
      

    【讨论】:

      【解决方案3】:

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

      在你作为参数传递给saga的函数中调用setState方法的组件

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

      【讨论】:

        【解决方案4】:

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

        我的解决方案是将调度包装在一个承诺中,并在一个传奇函数中调用解析和拒绝......

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

        希望对大家有所帮助。

        【讨论】:

          猜你喜欢
          • 2019-12-09
          • 1970-01-01
          • 2014-09-23
          • 1970-01-01
          • 2021-06-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多