Redux 重用传奇逻辑

Redux 重用传奇逻辑,redux,redux-saga,Redux,Redux Saga,我们有一个通用的表单组件,附带一个处理验证和提交的传奇 function* validateAndSubmit(action) { const errors = clientSideValidate(action.values); if (errors) { return yield put({type: SUBMIT_FAILED, formKey: action.formKey, errors: errors}); } try {

我们有一个通用的表单组件,附带一个处理验证和提交的传奇

function* validateAndSubmit(action) {
    const errors = clientSideValidate(action.values);
    if (errors) {
        return yield put({type: SUBMIT_FAILED, formKey: action.formKey, errors: errors});
    }

    try {
        const response = yield call(submitToTargetUrl(action.values, action.url));
        if (response.errors) {
            return yield put({type: SUBMIT_FAILED, formKey: action.formKey, errors: response.errors});
        }

        yield put({type: SUBMIT_SUCCESS, formKey: action.formKey});
    } catch (e) {
        yield put({type: SUBMIT_FAILED, formKey: action.formKey, errors: [e.message]});
    }
}

function* form() {
    yield takeEvery(SUBMITTED, validateAndSubmit);
}
现在,我们有了另一个组件,比如
UserForm
,它包装了通用表单组件。在提交时,我们希望将表单提交到后端,同时从外部API获取一些数据,等待两者完成,然后发送一些操作。这种逻辑将存在于其他文件中的另一个传奇中。重用
validateAndSubmit
逻辑的正确模式是什么?有没有办法做到这一点:

function* handleUserFormSubmit(action) {
    const [submitResult, fetchResult] = yield all([
        call(validateAndSubmitSaga),
        call(fetchOtherData),
    ]);

    // ...test for successful results for both

    if (allIsGood) {
        yield put({type: ALL_IS_GOOD});
    }
}

function* userForm() {
    yield takeEvery(USER_FORM_SUBMITTED, handleUserFormSubmit);
}

谢谢

我建议创建一个可重用的
validateAndSubmit
函数来处理验证和提交,如果有错误,它将返回一个错误。然后,使用此函数生成表单提交saga效果

async function reusableValidateAndSubmit(formValues, submitUrl) {
  try {
    const errors = clientSideValidate(formValues);
    if (errors) {
      return errors;
    }

    const response = await submitToTargetUrl(formValues, submitUrl);
    if (response.errors) {
      return response.errors;
    }

    return null;

  } catch (e) {
    console.error('@reusableValidateAndSubmit: ', e);
    return [e.message];
  }
}


function* handleFormSubmitSaga(action) {
  try {
    const { values, url, formKey } = action;
    const errors = yield call(reusableValidateAndSubmit, values, url);

    if (errors) {
      return yield put({type: SUBMIT_FAILED, formKey: formKey, errors: errors});
    }

    return yield put({type: SUBMIT_SUCCESS, formKey: formKey});  

  } catch (e) {
    return yield put({type: SUBMIT_FAILED, formKey: action.formKey, errors: [e.message]});
  }
}


function* form() {
  yield takeEvery(SUBMITTED, handleFormSubmitSaga);
}
对于
handleUserFormSubmit
,我不确定在您的用例中,如果
fetchOtherData
失败,您是否希望
validateAndSubmitSaga
失败,反之亦然。使用redux saga的all()会产生类似的效果

MDN中
Promise.all()
返回值的一个片段:

然后,当给定iterable中的所有承诺都已解析时,或者如果任何承诺被拒绝,则异步解析/拒绝该返回的承诺(只要堆栈为空)

据推测,这是您预期的行为,并且已经实现了上面的代码。您可以重用
reusableValidateAndSubmit
函数

function* handleUserFormSubmit(action) {
  const [submitError, fetchResult] = yield all([
    call(reusableValidateAndSubmit, action.values, action.url),
    call(fetchOtherData),
  ]);

  // ...test for successful results for both
  // submitError is null if submit was a success
  // fetchResult must have a value or return true if was a success
  if (!submitError && fetchResult) {
    yield put({type: ALL_IS_GOOD});
  }
}

我还建议您看看一些表单框架,您可以与redux(即)合作,因为它们在某些用例中也有帮助。

我们最终得到了一个稍微不同的解决方案。我们不是在打电话,而是在打电话:

function* handleUserFormSubmit(action) {
    const [submitResult, fetchResult] = yield all([
        yield take(SUBMIT_SUCCESS),
        yield take(FETCH_OTHER_DATA_SUCCESS),
    ]);

    // ...test for successful results for both

    if (allIsGood) {
        yield put({type: ALL_IS_GOOD});
    }
}

function* userForm() {
    yield takeEvery(USER_FORM_SUBMITTED, handleUserFormSubmit);
}
这样,另一个传奇可以不受干扰地完成它的事情,而这个传奇可以根据它自己的逻辑作出反应