redux-saga 中观察者的意义何在?
What is the point of watchers in redux-saga?
我刚接触 redux-saga,我对 Watchers 和 Generators 有点困惑
以下面这段代码为例,它是我的 sagas 文件的入口点
function* employeesSaga() {
yield all([
takeEvery(getType(employeeActions.login.request), handleLoginRequest),
takeEvery(getType(employeeActions.verifyLogin.request), handleVerifyLoginRequest),
takeEvery(getType(employeeActions.logout), handleLogout)
]);
}
我直接将每个 redux 调用连接到相应的处理程序。
但是有些人使用观察者,然后他们调用那个生成器中的处理程序。这样做的目的是什么?我应该使用那个模式吗?
此外,我注意到有些人用 while(true)
包裹他们的整个处理程序,这有必要吗?因为我的代码在没有它的情况下也能正常工作...
关于第一个问题
这可能只是可读性的问题。
观察者不是真正的“模式”,它们只是让您的代码更明确地表达其意图:
function* watchLoginRequest() {
yield takeEvery(getType(employeeActions.login.request), handleLoginRequest)
}
function* watchVerifyLoginRequest() {
yield takeEvery(getType(employeeActions.verifyLogin.request), handleVerifyLoginRequest)
}
function* watchLogout() {
yield takeEvery(getType(employeeActions.logout), handleLogout)
}
function* startWatchers() {
yield call(watchLoginRequest)
yield call(watchVerifyLoginRequest)
yield call(watchLogout)
}
function* employeesSaga() {
yield call(startWatchers)
}
第二题
可能你说的是这种流量:
function* watchLoginRequest() {
while (true) {
const action = yield take(getType(employeeActions.login.request))
yield call(handleLoginRequest, action)
}
}
区别:
while(true)-take-call 流程不允许同时执行单个处理程序的两个实例。它执行一个操作,然后阻塞调用,直到 handleLoginRequest()
完成。如果用户在处理程序完成之前单击登录按钮,则会错过相应的操作。
takeEvery() 流程允许并发处理程序执行。这可能不是你想要的。
Redux-saga 文档告诉 how takeEvery()
is implemented 幕后情况:
const takeEvery = (patternOrChannel, saga, ...args) => fork(function*() {
while (true) {
const action = yield take(patternOrChannel)
yield fork(saga, ...args.concat(action))
}
})
你看,takeEvery()
本身是非阻塞的(一个fork),它以非阻塞的方式执行处理程序(一个fork)。
第三个选项
还有takeLatest()
, which does allow concurrent handler execution, but if there is a previous instance of a handler executing, it cancels呢。 Redux-saga 文档也提供了它的内部实现。
我认为 while(true)-take-call 是最好的登录流程。您可能不希望并发登录。但是,如果您在 UI 级别阻止并发登录,这些流程是等效的,但 while(true)-take-call 是最明确和可读的。
我刚接触 redux-saga,我对 Watchers 和 Generators 有点困惑
以下面这段代码为例,它是我的 sagas 文件的入口点
function* employeesSaga() {
yield all([
takeEvery(getType(employeeActions.login.request), handleLoginRequest),
takeEvery(getType(employeeActions.verifyLogin.request), handleVerifyLoginRequest),
takeEvery(getType(employeeActions.logout), handleLogout)
]);
}
我直接将每个 redux 调用连接到相应的处理程序。
但是有些人使用观察者,然后他们调用那个生成器中的处理程序。这样做的目的是什么?我应该使用那个模式吗?
此外,我注意到有些人用 while(true)
包裹他们的整个处理程序,这有必要吗?因为我的代码在没有它的情况下也能正常工作...
关于第一个问题
这可能只是可读性的问题。
观察者不是真正的“模式”,它们只是让您的代码更明确地表达其意图:
function* watchLoginRequest() {
yield takeEvery(getType(employeeActions.login.request), handleLoginRequest)
}
function* watchVerifyLoginRequest() {
yield takeEvery(getType(employeeActions.verifyLogin.request), handleVerifyLoginRequest)
}
function* watchLogout() {
yield takeEvery(getType(employeeActions.logout), handleLogout)
}
function* startWatchers() {
yield call(watchLoginRequest)
yield call(watchVerifyLoginRequest)
yield call(watchLogout)
}
function* employeesSaga() {
yield call(startWatchers)
}
第二题
可能你说的是这种流量:
function* watchLoginRequest() {
while (true) {
const action = yield take(getType(employeeActions.login.request))
yield call(handleLoginRequest, action)
}
}
区别:
while(true)-take-call 流程不允许同时执行单个处理程序的两个实例。它执行一个操作,然后阻塞调用,直到
handleLoginRequest()
完成。如果用户在处理程序完成之前单击登录按钮,则会错过相应的操作。takeEvery() 流程允许并发处理程序执行。这可能不是你想要的。
Redux-saga 文档告诉 how takeEvery()
is implemented 幕后情况:
const takeEvery = (patternOrChannel, saga, ...args) => fork(function*() {
while (true) {
const action = yield take(patternOrChannel)
yield fork(saga, ...args.concat(action))
}
})
你看,takeEvery()
本身是非阻塞的(一个fork),它以非阻塞的方式执行处理程序(一个fork)。
第三个选项
还有takeLatest()
, which does allow concurrent handler execution, but if there is a previous instance of a handler executing, it cancels呢。 Redux-saga 文档也提供了它的内部实现。
我认为 while(true)-take-call 是最好的登录流程。您可能不希望并发登录。但是,如果您在 UI 级别阻止并发登录,这些流程是等效的,但 while(true)-take-call 是最明确和可读的。