我可以添加副作用来扫描吗
Can I add side-effects to scan
我有一个问题:“当鼠标按下时,创建一个矩形,移动时调整它的大小,当鼠标抬起时完成”。
我尝试使用 rxjs,但这不是很好的解决方案:
import { scan, mergeMap, takeUntil, fromEvent } from 'rxjs';
const mouseDown$ = fromEvent(document, 'mousedown');
const mouseUp$ = fromEvent(document, 'mouseup');
const mouseMove$ = fromEvent(document, 'mousemove');
function createNode() {
const node = document.createElement('DIV');
node.setAttribute('style', 'position: absolute; border: 1px solid red;');
document.body.appendChild(node);
return node;
}
mouseDown$
.pipe(
mergeMap(() => {
return mouseMove$.pipe(
takeUntil(mouseUp$),
scan((node, e: MouseEvent) => {
if (!node) {
let x = null;
x = createNode();
x.style.top = `${e.clientY}px`;
x.style.left = `${e.clientX}px`;
return x;
} else {
node.style.bottom = `${e.clientY}px`;
node.style.right = `${e.clientX}px`;
}
return node;
}, null)
);
})
)
.subscribe(() => {});
问题是副作用被添加到方法“扫描”
对于这个问题,你有更好的解决方案吗?
如果你想避免内部管道副作用(这通常是一件好事)你可以将你的逻辑分成两个不同的 Observables/Subscriptions
:
创建节点 Observable
let node = null
const createNode$ = mouseDown$.pipe(
switchMapTo(mouseMove$.pipe(
takeUntil(mouseUp$),
take(1)
))
)
createNode$.subscribe(createNode)
function createNode(e: MouseEvent) {
const node = document.createElement('DIV');
node.setAttribute('style', 'position: absolute; border: 1px solid red;');
document.body.appendChild(node);
x.style.top = `${e.clientY}px`;
x.style.left = `${e.clientX}px`;
return node;
}
更新节点 Obsservable
const updateNode$ = mouseDown$.pipe(
switchMapTo(mouseMove$.pipe(
takeUntil(mouseUp$),
skip(1)
))
)
updateNode$.subscribe(updateNode(node))
function updateNode(node: Node) {
return function(e: MouseEvent) {
node.style.bottom = `${e.clientY}px`;
node.style.right = `${e.clientX}px`;
}
}
与您的解决方案相比,我不喜欢上面的解决方案 - 它们在我看来都是平等的。这只是一种可能避免副作用的方法。关于何时以及为什么要避免副作用有多种意见。我个人尝试尽可能减少它们,但在某些情况下不值得这样做(或者我可能只是没有看到好的解决方案)。
我曾经问过一个关于的问题。答案可以为您提供一些详细信息,说明何时以及为何可以避免副作用。
我有一个问题:“当鼠标按下时,创建一个矩形,移动时调整它的大小,当鼠标抬起时完成”。 我尝试使用 rxjs,但这不是很好的解决方案:
import { scan, mergeMap, takeUntil, fromEvent } from 'rxjs';
const mouseDown$ = fromEvent(document, 'mousedown');
const mouseUp$ = fromEvent(document, 'mouseup');
const mouseMove$ = fromEvent(document, 'mousemove');
function createNode() {
const node = document.createElement('DIV');
node.setAttribute('style', 'position: absolute; border: 1px solid red;');
document.body.appendChild(node);
return node;
}
mouseDown$
.pipe(
mergeMap(() => {
return mouseMove$.pipe(
takeUntil(mouseUp$),
scan((node, e: MouseEvent) => {
if (!node) {
let x = null;
x = createNode();
x.style.top = `${e.clientY}px`;
x.style.left = `${e.clientX}px`;
return x;
} else {
node.style.bottom = `${e.clientY}px`;
node.style.right = `${e.clientX}px`;
}
return node;
}, null)
);
})
)
.subscribe(() => {});
问题是副作用被添加到方法“扫描” 对于这个问题,你有更好的解决方案吗?
如果你想避免内部管道副作用(这通常是一件好事)你可以将你的逻辑分成两个不同的 Observables/Subscriptions
:
创建节点 Observable
let node = null
const createNode$ = mouseDown$.pipe(
switchMapTo(mouseMove$.pipe(
takeUntil(mouseUp$),
take(1)
))
)
createNode$.subscribe(createNode)
function createNode(e: MouseEvent) {
const node = document.createElement('DIV');
node.setAttribute('style', 'position: absolute; border: 1px solid red;');
document.body.appendChild(node);
x.style.top = `${e.clientY}px`;
x.style.left = `${e.clientX}px`;
return node;
}
更新节点 Obsservable
const updateNode$ = mouseDown$.pipe(
switchMapTo(mouseMove$.pipe(
takeUntil(mouseUp$),
skip(1)
))
)
updateNode$.subscribe(updateNode(node))
function updateNode(node: Node) {
return function(e: MouseEvent) {
node.style.bottom = `${e.clientY}px`;
node.style.right = `${e.clientX}px`;
}
}
与您的解决方案相比,我不喜欢上面的解决方案 - 它们在我看来都是平等的。这只是一种可能避免副作用的方法。关于何时以及为什么要避免副作用有多种意见。我个人尝试尽可能减少它们,但在某些情况下不值得这样做(或者我可能只是没有看到好的解决方案)。
我曾经问过一个关于