React redux Sagas,等待 Saga 设置状态

React redux Sagas, wait for a Saga to set state

我有一些组件的代码如下:

const startLogin = (code) => {
  dispatch(login({ code }));
  const publicKeyFromLocalST = window.localStorage.getItem('push_public_key');
  setPublicKey(publicKeyFromLocalST);
  // etc

当我发送 saga login 时,它会在 localStorage 中存储一些数据。 我需要执行第 3 行 (setPublicKey),因为数据实际上确实在 localStorage 中。

如何“等待”dispatch(login({ code })); 在 setPublicKey 之前完成?

两个选项:

  1. 在worker saga中执行setPublicKey函数,你可以通过yield轻松控制worker saga中的工作流。
function* login(action) {
  const response = yield call(apiCall);
  if (response.error) {
    yield put({ type: actionType.LOGIN_FAIL });
  } else {
    yield put({ type: actionType.LOGIN_SUCCESS, data: response.data });
    const publicKeyFromLocalST = window.localStorage.getItem('push_public_key');
    setPublicKey(publicKeyFromLocalST);
  }
}
  1. Promisify dispatch(login({code})),你应该像这样创建一个辅助函数:
const loginAsyncCreator = (dispatch) => (payload) => {
  return new Promise((resolve, reject) => dispatch(loginCreator(payload, { resolve, reject })));
};

您需要通过 action.metaresolve/reject 传递给 worker saga,然后您可以决定何时解决或拒绝承诺。然后,您可以在事件处理程序中使用 async/await。请参阅以下示例:

import { call, put, takeLatest } from 'redux-saga/effects';
import { createStoreWithSaga } from '../../utils';
const actionType = {
  LOGIN: 'LOGIN',
  LOGIN_FAIL: 'LOGIN_FAIL',
  LOGIN_SUCCESS: 'LOGIN_SUCCESS',
};
function apiCall() {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve({ error: null, data: 'login success' });
    }, 2000);
  });
}

function* login(action) {
  console.log('action: ', action);
  const {
    meta: { resolve, reject },
  } = action;
  const response = yield call(apiCall);
  console.log('response: ', response);
  if (response.error) {
    yield put({ type: actionType.LOGIN_FAIL });
    yield call(reject, response.error);
  } else {
    yield put({ type: actionType.LOGIN_SUCCESS, data: response.data });
    yield call(resolve, response.data);
  }
}

function* watchLogin() {
  yield takeLatest(actionType.LOGIN, login);
}

const store = createStoreWithSaga(watchLogin);

function loginCreator(payload, meta) {
  return {
    type: actionType.LOGIN,
    payload,
    meta,
  };
}

const loginAsyncCreator = (dispatch) => (payload) => {
  return new Promise((resolve, reject) => dispatch(loginCreator(payload, { resolve, reject })));
};

const loginAsync = loginAsyncCreator(store.dispatch);

async function startLogin() {
  await loginAsync({ code: '1' });
  console.log('setPublicKey');
}

startLogin();

日志:

action:  {
  type: 'LOGIN',
  payload: { code: '1' },
  meta: { resolve: [Function (anonymous)], reject: [Function (anonymous)] }
}
response:  { error: null, data: 'login success' }
setPublicKey