【问题标题】:RXJS debounce and modify BehaviourSubjectRXJS 去抖动和修改 BehaviorSubject
【发布时间】:2019-04-08 05:11:52
【问题描述】:

我有这个工作,但我不确定这是否是最好的方法。我觉得每个方法中应该有一个更简单的方法——addTodo、deleteTodoById、updateTodo。

我正在使用 BehaviourSubject 来修改数组,但是当我更新时,我希望消除用户输入(或延迟)并在后台更新本地存储

如何改进和简化 RXJS 代码?

import { Injectable } from "@angular/core"
import { Todo } from "./todo"
import { BehaviorSubject, Observable } from 'rxjs'
import { take } from 'rxjs/operators'


@Injectable()
export class TodoService {
  todos:  BehaviorSubject<Todo[]> = new BehaviorSubject<Todo[]>([]);
  observable: Observable<Todo[]> =  this.todos.asObservable();

  getTodos(): Observable<Todo[]> {
    try {
      const todos: Todo[] = JSON.parse(localStorage.getItem('todos'))
      if(!todos) {
        return this.todos
      }
      this.todos.pipe(take(1)).subscribe(() => {
        return this.todos.next(todos)
      })
      return this.todos;
    } catch(err) {
      console.log('have no local storage')
    }
  }

  addTodo(todo: Todo): TodoService {
    this.todos.pipe(take(1)).subscribe(todos => {
      this.updateLocalStorage([...todos, todo])
      return this.todos.next([...todos, todo])
    })
    return this
  }

  deleteTodoById(id): TodoService {
    this.todos.pipe(take(1)).subscribe(todos => {
      const filteredTodos = todos.filter(t => t.id !== id)
      this.updateLocalStorage(filteredTodos)
      return this.todos.next(filteredTodos)
    })
    return this
  }


  updateTodo(id, title): void {
    this.todos.pipe(take(1)).subscribe((todos) => {
      const todo = todos.find(t => t.id === id)
      if(todo) {
        todo.title = title
        const newTodos = todos.map(t => (t.id === id ? todo : t))
        this.updateLocalStorage(newTodos)
        return this.todos.next(newTodos)
      }
    })
  }

  updateLocalStorage(todos):void {
    this.todos.subscribe(t => {
      setTimeout(() => {
        localStorage.setItem('todos', JSON.stringify(todos))
      }, 300)
      })
  }
}

【问题讨论】:

    标签: javascript angular rxjs


    【解决方案1】:

    到目前为止,我不确定您想要改进什么。

    我创建了这个 mooked 应用程序来向您展示我是如何管理这种操作的。

    在这个应用程序上,我没有使用来自 Angular 的ReactiveFormModule,它可以轻松地抽象这部分:

    const inputElement = document.getElementById('input') as HTMLInputElement;
    const onChange$ = fromEvent(
      inputElement, // In keyup from input field.
      'keyup'
    ).pipe(
      debounceTime(1000), // Delay the user input
      map(() => inputElement.value) // Transform KeyboardEvent to input value string.
    );
    

    通过这样做

       <input
           type="text" 
           name="title"
           [formControl]="title"
       >
    
    export class FooComponent implement OnInit {
        title: FormControl = new FormControl();
        ngOnInit() {
          this.title.valueChanges.pipe(debounceTime(1000)).subscribe(title => {
            // Do something with your debounced data.
          })
        }
    }
    

    那么你可以按照这个逻辑:

    export class TodoService {
      private _todos$: BehaviorSubject<Todo[]>;
      private _todos: Todo[];
    
      constructor() {
          this._todos = (this.hasLocalStorage())?this.getLocalStorage():[];
          this._todos$ = new BehaviorSubject(this._todos);
      }
    
      add(todo: Todo) {
        this._todos.push(todo);
        this.refresh();
      }
    
      edit(id: number, title: string) {
        // Find by id and copy current todo.
        const todo = {
          ...this._todos.find(todo => todo.id === id)
        };
        // Update title
        todo.title = title;
        // Update todos reference
        this._todos = [
          // Find any other todos.
          ...this._todos.filter(todo => todo.id !== id),
          todo
        ];
        this.refresh();
      }
    
      get todos$(): Observable<Todo[]> {
        return this._todos$.asObservable();
      }
      private refresh() {
        this._todos$.next([...this._todos]);
        localStorage.setItem('todos', JSON.stringify(this._todos));
      }
    
      private hasLocalStorage(): boolean {
          return (localStorage.getItem('todos') !== null);
      }
    
      private getLocalStorage(): Todo[] {
        return JSON.parse(localStorage.getItem('todos'));
      }
    }
    

    1/ 这里我有 2 个属性,一个是我的商店,我将在其中保留对我所有待办事项的引用,第二个是我的 BehaviorSubject,它用于在我的商店更新时通知我的应用程序的其余部分。

    2/ 在我的构造函数中,我通过空数组或 localStorage 数据(如果存在)初始化这两个属性。

    3/ 我有refresh 方法可以做两件事,更新我的两个属性。

    4/ 在添加/编辑/删除操作时,我将其作为常规数组操作执行,然后我调用“刷新”。

    live coding

    【讨论】:

    • 谢谢 - 它几乎证实了我的一些想法 - 如果我想消除输入的抖动,我必须将事件观察器附加到元素。
    • 我强烈建议您使用 Angular 中的 ReactiveFormModule,它可以做同样的事情,但抽象级别很高。喜欢我回答的FormControl 部分。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-22
    • 2021-02-20
    • 2021-04-14
    • 1970-01-01
    相关资源
    最近更新 更多