问题是我有多个输入和一个按钮来保存数据。我在我的组件中有此方法:
handleClick(e) {
e.preventDefault();
this.props.newEmail ? this.props.onSaveNewEmail(this.props.newEmail) : null;
this.props.newName ? this.props.onSaveNewName(this.props.newName) : null;
}
此方法在我的redux传奇中捕获:
export function* isName() {
const name = yield select(makeNewNameSelector());
...
// validation name
if (!re.test(name)) {
...
} else {
// ! OK, I CAN UPDATE NAME BECAUSE NEW NAME IS OK
}
}
export function* isEmail() {
const email = yield select(makeNewEmailSelector());
const requestURL = `/api/users/isEmail/${email}`;
...
// validation email
if (!re.test(email)) {
...
} else {
try {
const response = yield call(request, requestURL);
if (!response.isEmail) {
// ! OK, I CAN UPDATE EMAIL BECAUSE IT DOESN'T HAVE IN MY DB MYSQL
}
} catch (err) {
...
}
}
}
// this method send request PUT and this can update data:
function* saveData() {
const name = yield select(makeNewNameSelector());
const email = yield select(makeNewEmailSelector());
...
try {
const response = yield call(request, requestURL, {
method: 'PUT',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: `Bearer ${jwt}`,
},
body: JSON.stringify({
name,
email,
}),
});
if (response.success) {
name ? yield put(enterNewNameSuccessAction()) : null;
email ? yield put(enterNewEmailSuccessAction()) : null;
yield put(saveDataSuccessAction());
}
} catch (err) {
...
}
}
export default function* settingsPageSaga() {
yield takeLatest(ENTER_NEW_NAME, isName);
yield takeLatest(ENTER_NEW_EMAIL, isEmail);
}
现在我应该只调用一次我的saveData()
方法吗?
如果我在评论中放了一个yield call(saveData)
,它会起作用,但这会发送一个两个请求!我只想发送一个PUT请求。
如果要更改电子邮件,则必须等到我的代码检查数据库中是否存在此类电子邮件。如果没有,则只能更改操作。
答案 0 :(得分:0)
一步一步,针对您的特定实现的解决方案可能是以下方法:
redux-saga
导入更多效果:import { cancel, fork} from "redux-saga/effects";
isEmail
传奇在开始时就调度一个动作,以让其他sagas截获它,然后用reducer设置emailCheckRunning
标志。此操作可能是yield put(EMAIL_CHECK_START)
SAVE_EMAIL
用减速器将emailCheckRunning
标志更新为false
// ! OK, I CAN UPDATE NAME BECAUSE NEW NAME IS OK
,而是派遣一个yield put(SAVE_NAME)
之类的动作// ! OK, I CAN UPDATE EMAIL BECAUSE IT DOESN'T HAVE IN MY DB MYSQL
,而是派遣一个yield put(SAVE_EMAIL)
之类的动作settingsPageSaga
中产生/分叉一个新的传奇(它们之间的区别与您的示例代码无关,read here如果您想了解更多)yield fork(saveDataSaga);
saveDataSaga
传奇看起来像这样function* saveDataSaga() {
let task;
while(true) {
// both ENTER_NEW_NAME and ENTER_NEW_EMAIL will start a new `saveDataNetworkFlow` saga
yield take([ENTER_NEW_NAME, ENTER_NEW_EMAIL]);
// but, before starting a new one, it cancels the previously forked `saveDataNetworkFlow` (if any)
if(task) {
yield cancel(task);
}
task = yield fork(saveDataNetworkFlow);
}
}
saveDataNetworkFlow
传奇是function* saveDataNetworkFlow() {
const action = yield take([SAVE_NAME, SAVE_EMAIL]);
if(action.type === SAVE_NAME) {
// wait some milliseconds to let the `isEmail` saga run
yield wait(100);
}
// I assume that the `emailCheckRunning` flag is stored on top of your state, update it based on the shape of your own state
const emailCheckRunning = yield select((globalState) => globalState.emailCheckRunning);
if(emailCheckRunning) {
yield take(SAVE_EMAIL);
}
yield call(saveData);
}
让我们分析不同的情况:
简单的CHANGE_NAME
操作
saveDataSaga
传奇取消了以前的saveDataNetworkFlow
传奇SAVE_NAME
操作解锁了saveDataNetworkFlow
传奇saveDataNetworkFlow
传奇故事等待100毫秒saveDataNetworkFlow
称为saveData
传奇具有有效AJAX检查的简单CHANGE_EMAIL
操作
saveDataSaga
传奇取消了以前的saveDataNetworkFlow
传奇SAVE_EMAIL
将解锁saveDataNetworkFlow
传奇SAVE_EMAIL
操作将一个reducer设置为emailCheckRunning
为false)saveDataNetworkFlow
呼叫saveData
传奇具有无效AJAX检查的简单CHANGE_EMAIL
操作
saveDataSaga
传奇取消了以前的saveDataNetworkFlow
传奇SAVE_EMAIL
将解锁saveDataNetworkFlow
传奇saveDataNetworkFlow
等待SAVE_EMAIL
操作SAVE_EMAIL
不会被派发,saveDataNetworkFlow
的传奇永无止境,最终将在未来被取消 CHANGE_NAME
和CHANGE_EMAIL
具有有效的AJAX检查
saveDataSaga
传奇取消了以前的saveDataNetworkFlow
传奇SAVE_NAME
操作解锁了saveDataNetworkFlow
传奇saveDataNetworkFlow
传奇故事等待100毫秒saveDataNetworkFlow
等待SAVE_EMAIL
操作isEmail
传奇开始派发SAVE_EMAIL
saveDataNetworkFlow
呼叫saveData
传奇 CHANGE_NAME
和CHANGE_EMAIL
具有无效的AJAX检查
saveDataSaga
传奇取消了以前的saveDataNetworkFlow
传奇SAVE_NAME
操作解锁了saveDataNetworkFlow
传奇saveDataNetworkFlow
传奇故事等待100毫秒saveDataNetworkFlow
等待SAVE_EMAIL
操作SAVE_EMAIL
不会被派发,saveDataNetworkFlow
的传奇永无止境,最终将在未来被取消 CHANGE_NAME
或CHANGE_EMAIL
操作在先前的传奇运行时分派
isName
和isEmail
sagas实施相同的取消逻辑,以避免任何并发问题,在这里您可以找到how to do it(这是相同基础上的指南我的解决方案)我希望它会有所帮助,如果您需要更多帮助,请告诉我
请注意:
saveData
仍在等待服务器响应的同时用户提交了两次表单,则两个AJAX请求将到达服务器。您可以使用一些化简工具来管理Redux状态,并避免用户在第一个请求尚未完成时提交表单。
取消AJAX请求没有任何意义,因为一旦它离开客户端,它可能已经在服务器上生效。import { cancelled } from 'redux-saga/effects'
function* saga() {
try {
// ... your code
} finally {
if (yield cancelled())
// the saga has been cancelled
}
}