【问题标题】:Dispatch Action Inside A Promise Then Function In A Saga在 Promise 中调度动作然后在 Saga 中运行
【发布时间】:2018-08-11 19:14:00
【问题描述】:

我有一个 saga(使用 redux-saga)调用一个 POST 到 API 端点的函数(使用 axios)。通过 axios 进行更深层次的 API 调用会返回一个 Promise。我想在promise 的then() 方法中调度操作,但我显然不能使用yieldput() 似乎没有放任何东西。这样做的正确方法是什么?

这是传奇:

export function* loginFlow(action) {
  try {
    const {username, password} = action.payload;
    const responsePromise = yield call(login, {username, password, isRegistering: false});
    yield responsePromise
            .then(result => {
              console.log('loginFlow responsePromise result', result);
              put(creators.queueLoginSucceededAction()); // doesn't work
              put(push('/')); // doesn't work
            })
            .catch(err => {
              console.log('loginFlow responsePromise err', err);
              put(creators.queueLoginFailedAction()); // doesn't work
            });
  }
  catch(err) {
    console.log(err);
    yield put(creators.queueLoginFailedAction());
  }
}

这是被调用的函数:

export function* login(options) {
  try {
    // if we are already logged in, via token in local storage,
    // then skip checking against server
    if( store.get('token') ) {
      return Promise.resolve('Already logged in.');
    }

    // query server for valid login, returns a JWT token to store
    const hash = yield bcrypt.hashSync(options.password, 10);
    yield put(creators.queueLoginHttpPostedAction());
    return axios.post('/auth/local', {
              params: {
                username: options.username,
                password: hash,
                hash:     true,
              }
            })
            .then(result => {
              console.log('api>auth>login>result', result);
              put(creators.queueLoginHttpSucceededAction()); // doesn't work
              return Promise.resolve('Login successful');
            })
            .catch(err => {
              console.log('api>auth>login>err', err);
              put(creators.queueLoginHttpFailedAction()); // doesn't work
              return Promise.reject(err.message);
            });
  }
  catch (err) {
    yield put(creators.queueLoginHttpFailedAction());
    return Promise.reject('Login could not execute');
  }
}

【问题讨论】:

  • 如果你 yield 承诺 redux-saga 会等待它并给你响应,所以这行:const responsePromise = yield call(login, {username, password, isRegistering: false}); 实际上应该是 const result = yield call(login, {username, password, isRegistering: false});。所以你真的不需要使用then

标签: redux promise react-redux redux-saga


【解决方案1】:

saga 'yield call' 将等待返回的 Promise 完成。如果它失败了,它会抛出一个错误,所以你可以使用普通的 try-catch 代替使用 'then' 和 'catch' 来代替 Promise。

Redux Saga 文档更详细地解释了这一点 - 绝对值得一读:

https://redux-saga.js.org/docs/basics/ErrorHandling.html

换句话说,下面的login(options) 函数将执行HTTP 请求,只要它没有返回被拒绝的promise,它就会继续将成功的操作排队并将用户重定向回来。如果它确实发回了一个被拒绝的承诺,它会立即跳转到 'catch' 块。

更正了登录流程:

export function * loginFlow(action) {
  try {
    const {username, password} = action.payload;
    const responsePromise = yield call(login, {username, password, isRegistering: false});
    console.log('loginFlow responsePromise result', result);
    yield put(creators.queueLoginSucceededAction());
    yield put(push('/'));
  }
  catch(err) {
    console.log('loginFlow responsePromise err', err);
    yield put(creators.queueLoginFailedAction());
  }
}

而对于实际的登录过程:

export function * login(options) {
  // if we are already logged in, via token in local storage,
  // then skip checking against server
  if( store.get('token') ) {
    return Promise.resolve('Already logged in.');
  }

  // query server for valid login, returns a JWT token to store
  const hash = yield bcrypt.hashSync(options.password, 10);
  yield put(creators.queueLoginHttpPostedAction());

  try {
    yield call(
      axios.post, 
      '/auth/local', 
      { params: { username: options.username, password: hash, hash: true } }
    )

    console.log('api>auth>login>result', result);
    yield put(creators.queueLoginHttpSucceededAction()); // doesn't work
    return Promise.resolve('Login successful');

  } catch(err) {
    console.log('api>auth>login>err', err);
    yield put(creators.queueLoginHttpFailedAction()); // doesn't work
    return Promise.reject(err.message);
  }
}

【讨论】:

    猜你喜欢
    • 2020-01-14
    • 2019-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-18
    • 1970-01-01
    • 2023-03-09
    相关资源
    最近更新 更多