首页 > 解决方案 > 使用主题的 Rxjs 在反应文本输入组件上去抖动不会在无状态/功能组件上批量输入文本

问题描述

我正在尝试更深入地研究 rxjs 并发现了一个问题,即我尝试去抖动的输入字段在每次按键时调度一个事件,去抖动只保留输出,但会生成如下树:

a
as(delay - waits 200ms, then fires the rest synchronously)
asd
asdf
asdfg 
....

相同的代码在类组件(https://stackoverflow.com/a/44300853/1356046)中按预期工作,但无法理解为什么它不适用于无状态组件。这是一个示例:https ://stackblitz.com/edit/react-hzhrmf - 您可以看到每次击键都会触发 useState 更新。

非常感谢。

标签: javascriptrxjsdebouncing

解决方案


React 不断调用你的函数来渲染组件。因此,主题不断被重新创建。

使用带有 useState 的工厂来保留主题并使用 useEffect 确保订阅只进行一次应该可以解决您的问题。

像这样的东西:

import React, { Component, useState, useEffect, useRef } from 'react';
import { render } from 'react-dom';
import { debounceTime, map, tap, distinctUntilChanged } from 'rxjs/operators';
import { fromEvent, Subject } from 'rxjs';

import './style.css';
const App = props => {
  const [queryName, setQueryName] = useState("");
  const [debouncedName, setDebouncedName] = useState("");
  const [onSearch$] = useState(()=>new Subject());
  useEffect(() => {
    const subscription = onSearch$.pipe(
      debounceTime(400),
      distinctUntilChanged(),
      tap(a => console.log(a))
    ).subscribe(setDebouncedName);
  }, [])
  const handleSearch = e => {
    setQueryName(e.target.value);
    onSearch$.next(e.target.value);
  };

  return (
    <div>
      <input
        placeholder="Search Tags"
        value={queryName}
        onChange={handleSearch}
      />
      <p>Debounced: {debouncedName}</p>
    </div>
  );
}

render(<App />, document.getElementById('root'));

推荐阅读