所以我刚开始尝试学习 rxjs 并决定在我目前正在使用 React 开发的 UI 上实现它(我有时间这样做,所以我就去做了)。然而,我仍然很难理解它实际上是如何工作的……不仅仅是“基本”的东西,比如什么时候实际使用 Subject 和什么时候使用 Observable,或者什么时候只使用 React 的本地状态,还有如何链接方法等等。但这太宽泛了,所以这是我遇到的具体问题。
假设我有一个 UI,其中有一个过滤器(按钮)列表,这些过滤器(按钮)都可以点击。每当我点击其中一个时,我首先要确保接下来的操作会去抖动(以避免太快和太频繁地发出网络请求),然后我想确保如果它被点击(事件),它将被插入一个数组,如果再次单击它,它将离开数组。现在,这个数组最终应该包括所有当前被点击或选择的按钮(过滤器)。
然后,当去抖时间结束时,我希望能够使用该数组并通过 Ajax 将它发送到我的服务器并用它做一些事情。
import React, { Component } from 'react';
import * as Rx from 'rx';
export default class CategoryFilter extends Component {
constructor(props) {
super(props);
this.state = {
arr: []
}
this.click = new Rx.Subject();
this.click
.debounce(1000)
// .do(x => this.setState({
// arr: this.state.arr.push(x)
// }))
.subscribe(
click => this.search(click),
e => console.log(`error ---> ${e}`),
() => console.log('completed')
);
}
search(id) {
console.log('search --> ', id);
// this.props.onSearch({ search });
}
clickHandler(e) {
this.click.onNext(e.target.dataset.id);
}
render() {
return (
<section>
<ul>
{this.props.categoriesChildren.map(category => {
return (
<li
key={category._id}
data-id={category._id}
onClick={this.clickHandler.bind(this)}
>
{category.nombre}
</li>
);
})}
</ul>
</section>
);
}
}
我可以在没有 RxJS 的情况下轻松地解决这个问题,我自己检查数组并使用一个小的去抖等等,但我选择这样做是因为我实际上想尝试理解它然后能够在更大的场景。但是,我必须承认我对最佳方法一无所知。这涉及很多方法和不同的东西(包括模式和库),我只是被困在这里。
无论如何,欢迎提供任何帮助(以及关于如何改进此代码的一般评论)。提前致谢!
--------------------------------更新----- ----------------------------
我已经在我的代码中实现了 Mark 的部分建议,但这仍然存在两个问题:
1- 我仍然不确定如何过滤结果,以便数组只保存被单击(和事件)的按钮的 ID。因此,换句话说,这些将是操作:
- 点击一个按钮一次 -> 将其 ID 放入数组
- 再次点击同一个按钮(可能是在第一次点击之后 单击或在任何其他时间)-> 从数组中删除其 ID。
这必须起作用才能通过 ajax 实际发送带有正确过滤器的数组。现在,我什至不确定这是否是 RxJS 的可能操作,但可以梦想......(另外,我愿意打赌它是)。
2- 也许这是一个更大的问题:当我在这个 View 中时,我如何才能真正维护这个数组。我猜我可以为此使用 React 的本地状态,只是不知道如何使用 RxJS 来实现。因为就目前而言,缓冲区仅返回在去抖动时间结束之前已被单击的按钮,这意味着它每次都“创建”一个新数组。这显然不是正确的行为。它应始终指向现有数组并过滤并使用它。
这是当前代码:
import React, { Component } from 'react';
import * as Rx from 'rx';
export default class CategoryFilter extends Component {
constructor(props) {
super(props);
this.state = {
arr: []
}
this.click = new Rx.Subject();
this.click
.buffer(this.click.debounce(2000))
.subscribe(
click => console.log('click', click),
e => console.log(`error ---> ${e}`),
() => console.log('completed')
);
}
search(id) {
console.log('search --> ', id);
// this.props.onSearch({ search });
}
clickHandler(e) {
this.click.onNext(e.target.dataset.id);
}
render() {
return (
<section>
<ul>
{this.props.categoriesChildren.map(category => {
return (
<li
key={category._id}
data-id={category._id}
onClick={this.clickHandler.bind(this)}
>
{category.nombre}
</li>
);
})}
</ul>
</section>
);
}
}
再次感谢大家!
最佳答案
使用 Rx.Observable.fromevent
(参见 https://github.com/Reactive-Extensions/RxJS/blob/master/doc/gettingstarted/events.md#converting-a-dom-event-to-a-rxjs-observable-sequence)使您的过滤器项成为可观察的点击事件流 - 它理解用于点击处理的多元素选择器。
您希望一直接收点击事件,直到发生反跳(用户已启用/禁用她想要使用的所有过滤器)。您可以使用 Buffer
operator为此,使用 closingSelector
需要在关闭缓冲区和发出缓冲值时发出一个值。
但留下了如何知道当前实际状态的问题。
更新
使用 .scan
运算符创建 filterState 数组并对其进行去抖动似乎要容易得多。
const sources = document.querySelectorAll('input[type=checkbox]');
const clicksStream = Rx.Observable.fromEvent(sources, 'click')
.map(evt => ({
name: evt.target.name,
enabled: evt.target.checked
}));
const filterStatesStream = clicksStream.scan((acc, curr) => {
acc[curr.name] = curr.enabled;
return acc
}, {})
.debounce(5 * 1000)
filterStatesStream.subscribe(currentFilterState => console.log('time to do something with the current filter state: ', currentFilterState);
关于javascript - RxJS 和 React 多次点击元素形成单个数据数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40392078/