use*_*596 17 ecmascript-6 reactjs redux redux-saga
我正在努力让redux-saga与onmessage听众合作.我不知道为什么我的工作不起作用.
我有以下设置.
// sagas.js
import { take, put } from 'redux-saga';
import {transactions} from "./actions";
function* foo (txs) {
console.log("yielding"); // appears in console
yield put(transactions(txs)); // action *is not* dispatched
console.log("yielded"); //appears in console
}
const onMessage = (event) => {
const txs = JSON.parse(event.data);
const iter = foo(txs);
iter.next(); // do I really need to do this?
};
function* getTransactions() {
while(yield take('APP_LOADED')) {
const stream = new EventSource(eventSourceUrl);
stream.onopen = onOpen;
stream.onmessage = onMessage;
stream.onerror = onError;
// this is just testing that `yield put` works
yield put(transactions([{baz : 42}])); //this action *is* dispatched
}
};
Run Code Online (Sandbox Code Playgroud)
当APP_LOADED调度动作被getTransactions调用时,流被打开并且当从服务器接收数据时调用onMessage侦听器,但是在调用yield put(transactions(txs))生成器时我没有运气调度动作foo.
谁能告诉我我做错了什么?
Yas*_*afi 32
Saga只能从另一个Saga(使用yield foo()或yield call(foo))中调用.
在你的例子中,foo从正常函数(onMessage回调)内部调用Saga ,因此它只返回迭代器对象.通过从Saga中产生迭代器(或对生成器的调用),我们允许redux-saga中间件拦截该调用并运行迭代器以解析所有生成的效果.但是在你的代码中,stream.onmessage = onMessage只需做一个简单的分配,这样中间件就不会注意到任何东西.
至于主要问题.Sagas通常从Redux商店获取事件.您可以使用runSaga将saga连接到自定义输入/输出源,但将其应用于上述用例并不是一件容易的事.因此,我将仅使用call效果提出另一种选择.但是,为了介绍它,我们必须从事件的推动视角转向拉动视角.
处理事件的传统方法是在某些事件源上注册一些事件侦听器.就像在上面的例子中分配onMessage回调一样stream.onmessage.每个事件发生都被推送到侦听器回调.事件源完全控制.
redux-saga采用了不同的模式:Sagas 拉出了理想的赛事.作为回调,它们通常会进行一些处理.但是他们完全可以控制下一步该做什么:他们可能会选择再次拉同一个事件 - 模仿回调模型 - 但他们并没有被迫.他们可能选择拉另一个事件,启动另一个传奇以接收中继甚至终止他们的执行.即他们控制着自己的进步逻辑.所有事件源都可以解决未来事件的查询.
要集成外部推送源,我们需要将事件源从推送模型转换为拉模型; 即我们必须构建一个事件迭代器,我们可以从事件源中提取未来的事件
这是onmessage从一个派生迭代器的例子EventSource
function createSource(url) {
const source = new EventSource(url)
let deferred
source.onmessage = event => {
if(deferred) {
deferred.resolve(JSON.parse(event.data))
deferred = null
}
}
return {
nextMessage() {
if(!deferred) {
deferred = {}
deferred.promise =
new Promise(resolve => deferred.resolve = resolve)
}
return deferred.promise
}
}
}
Run Code Online (Sandbox Code Playgroud)
上面的函数返回一个对象,其中包含一个nextMessage可用于提取未来消息的方法.调用它将返回一个Promise,它将使用下一个传入消息解析.
拥有createSourceAPI功能.我们现在可以通过简单的call效果使用它
function* watchMessages(msgSource) {
let txs = yield call(msgSource.nextMessage)
while(txs) {
yield put(transactions(txs))
txs = yield call(msgSource.nextMessage)
}
}
function* getTransactionsOnLoad() {
yield take('APP_LOADED')
const msgSource = yield call(createSource, '/myurl')
yield fork(watchMessages, msgSource)
}
Run Code Online (Sandbox Code Playgroud)
您可以找到上述代码的实时运行演示.
上述方法的一个优点是,它使内部萨加斯代码完全声明性(仅使用声明性形式fork和call)
| 归档时间: |
|
| 查看次数: |
4361 次 |
| 最近记录: |