Frage RxJS und Reagieren mehrerer angeklickter Elemente, um ein einzelnes Datenarray zu bilden


Also habe ich gerade erst begonnen, rxjs zu lernen und entschied, dass ich es auf einer Benutzeroberfläche implementieren würde, mit der ich gerade arbeite (ich habe Zeit dafür, also habe ich es gemacht). Es fällt mir jedoch immer noch schwer, mich daran zu gewöhnen, wie es wirklich funktioniert ... Nicht nur "grundlegende" Dinge wie zum Beispiel, wann man ein Subjekt tatsächlich verwenden soll und wann man ein Observable verwenden sollte, oder wann man nur den lokalen Status von React verwenden sollte , aber auch, wie man Methoden kettet und so weiter. Das ist aber alles zu weit, also hier ist das spezifische Problem, das ich habe.

Angenommen, ich habe eine Benutzeroberfläche mit einer Liste von Filtern (Schaltflächen), die alle anklickbar sind. Jedes Mal, wenn ich auf eines von ihnen klicke, möchte ich zunächst sicherstellen, dass die folgenden Aktionen entprellen (um zu vermeiden, dass Netzwerkanfragen zu früh und zu oft gestellt werden), dann möchte ich sicherstellen, dass, wenn darauf geklickt wird ( aktiv), wird es in ein Array geschoben und wenn es erneut angeklickt wird, verlässt es das Array. Jetzt sollte dieses Array schließlich alle Schaltflächen (Filter) enthalten, die aktuell angeklickt oder ausgewählt sind.

Dann, wenn die Entprellzeit beendet ist, möchte ich in der Lage sein, dieses Array zu verwenden und es über Ajax an meinen Server zu senden und einige Sachen damit zu tun.

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>
    );
 }
}

Ich könnte das ohne RxJS leicht machen und einfach das Array selbst überprüfen und eine kleine Entprellung verwenden und was nicht, aber ich entschied mich für diesen Weg, weil ich wirklich versuchen möchte, es zu verstehen und dann in größeren Szenarien verwenden zu können. Allerdings muss ich zugeben, dass ich bei der besten Vorgehensweise sehr verloren bin. Es gibt so viele Methoden und verschiedene Dinge, die damit zusammenhängen (sowohl das Muster als auch die Bibliothek) und ich stecke hier einfach fest.

Wie auch immer, jede und jede Hilfe (sowie allgemeine Kommentare zur Verbesserung dieses Codes) sind willkommen. Danke im Voraus!

---------------------------------AKTUALISIEREN---------------------------------

Ich habe einen Teil von Marks Vorschlag in meinen Code implementiert, aber das stellt immer noch zwei Probleme dar:

1- Ich weiß immer noch nicht, wie ich die Ergebnisse filtern soll, damit das Array nur IDs für die angeklickten (und aktiven) Schaltflächen enthält. Mit anderen Worten, dies wären die Aktionen:

  • Klicken Sie einmal auf eine Schaltfläche -> lassen Sie ihre ID in Array gehen
  • Klicken Sie erneut auf den gleichen Knopf (es könnte direkt nach dem ersten sein) klicke oder zu irgendeiner anderen Zeit) -> entferne seine ID aus dem Array.

Dies muss funktionieren, um das Array mit den richtigen Filtern über Ajax zu senden. Nun, ich bin mir nicht einmal sicher, dass dies eine mögliche Operation mit RxJS ist, aber man kann träumen ... (Auch ich wette, dass es so ist).

2 - Vielleicht ist dies ein noch größeres Problem: Wie kann ich dieses Array beibehalten, während ich auf dieser Ansicht bin? Ich vermute, dass ich dafür den lokalen Zustand von React verwenden könnte, ich weiß einfach nicht, wie ich es mit RxJS machen soll. Denn wie es derzeit ist, gibt der Puffer nur die Schaltfläche (n) zurück, auf die geklickt wurde / wurde, bevor die Entprellzeit abgelaufen ist, was bedeutet, dass sie jedes Mal ein neues Array "erstellt". Das ist eindeutig nicht das richtige Verhalten. Es sollte immer auf ein vorhandenes Array zeigen und filtern und damit arbeiten.

Hier ist der aktuelle Code:

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>
    );
 }
}

Danke nochmal!


7
2017-11-03 00:43


Ursprung


Antworten:


Machen Sie Ihre Filterelemente zu beobachtbaren Streams von Klickereignissen mit Rx.Observable.fromevent (sehen https://github.com/Reactive-Extensions/RxJS/blob/master/doc/gettingstarted/events.md#converting-a-dom-event-to-a-rxjs-observable-sequence) - es versteht einen Multi-Element-Selektor für die Click-Handhabung.

Sie möchten weiterhin Klickereignisse erhalten, bis eine Entprellung ausgelöst wurde (der Benutzer hat alle Filter aktiviert / deaktiviert, die er verwenden möchte). Du kannst den ... benutzen Buffer  Operator dafür mit einem closingSelector Dieser muss einen Wert ausgeben, wenn der Puffer geschlossen und die gepufferten Werte ausgegeben werden sollen.

Hinterlässt aber das Problem, wie man den aktuellen Ist-Zustand kennt.

AKTUALISIEREN

Es scheint viel einfacher zu sein, das zu verwenden .scan Operator, um Ihr FilterState-Array zu erstellen und diese zu entprellen.

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);

(https://jsfiddle.net/crunchie84/n1x06016/6/)


0
2017-11-03 09:00