响应文本输入组件上的 Rxjs 去抖动

IT技术 reactjs rxjs
2021-04-20 20:21:44

我有以下react组件

<input className={styles.incSrchTextBox} type="text" name="search" placeholder="Search.."
   onChange={this.onChange} />


onChange(e) {
    const newText = e.target.value;
    console.log(newText);
    this.setState({ searchText: newText });
}

我如何在 rxjs 上使用去抖动?

3个回答

您将需要从更改事件中创建可观察对象(例如使用主题),然后对其进行去抖动。

这是为您提供的功能齐全的示例:

class Search extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      search: '',
      debounced: '',
    };
    this.onSearch$ = new Rx.Subject();
    this.onSearch = this.onSearch.bind(this);
  }
  componentDidMount(){
    this.subscription = this.onSearch$
      .debounceTime(300)
      .subscribe(debounced => this.setState({ debounced }));
  }
  
  componentWillUnmount() {
    if (this.subscription) {
      this.subscription.unsubscribe();
    }
  }
  
  onSearch(e) {
    const search = e.target.value;
    this.setState({ search });
    this.onSearch$.next(search);
  }

  render() {
    const { search, debounced } = this.state;
    return (
      <div>
        <input type="text" value={search} onChange={this.onSearch} />
        <div>debounced value: {debounced}</div>
      </div>
    );
  }
}

ReactDOM.render(
  <Search />,
  document.getElementById('root')
);
<script src="https://unpkg.com/rxjs@5.4.0/bundles/Rx.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

我不能在不创建主题的情况下做这样的事情 const example = Rx.Observable .fromEvent(input, 'keyup') .map(i => i.currentTarget.value); //在按键之间等待 .5 秒以发出当前值 //丢弃所有其他值 const debouncedInput = example.debounceTime(500);
2021-06-02 20:21:44
是的,但是当你已经有了 React 时直接使用 DOM 并不是一个好主意
2021-06-02 20:21:44
从 RxJs 6 开始,您需要使用管道运算符进行去抖动 this.onSearch$.pipe(debounceTime(300)).subscribe(...)
2021-06-06 20:21:44

我同意 Oles Savluk 的例子。此外,我将从组件中提取主题逻辑。它不需要存在于组件内部,因为它没有状态,而且我认为这也使组件更易于理解。

另外:该示例已更新为使用 RxJS 6.2.2

const { Subject } = rxjs;
const { debounceTime } = rxjs.operators;

const onSearch$ = new rxjs.Subject().pipe(
    debounceTime(300)
);

class Search extends React.Component {
  constructor(props) {
    super(props);
    
    this.state = {
      search: '',
      debounced: '',
    };
  }

  componentDidMount(){
    this.subscription = onSearch$.subscribe(
        debounced => this.setState({ debounced })
    );
  }
  
  componentWillUnmount() {
    if (this.subscription) {
      this.subscription.unsubscribe();
    }
  }
  
  onSearch = (e) => {
    const search = e.target.value;
    this.setState({ search });
    onSearch$.next(search);
  }

  render() {
    const { search, debounced } = this.state;
    return (
      <div>
        <input type="text" value={search} onChange={this.onSearch} />
        <div>debounced value: {debounced}</div>
      </div>
    );
  }
}

ReactDOM.render(
  <Search />,
  document.getElementById('root')
);
<script src="https://unpkg.com/rxjs@6.2.2/bundles/rxjs.umd.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

这将是Refract 的一个很好的用例

第一步是将输入拉出到一个单独的组件中:

const Input = ({ onChange, value }) => (
    <input type="text" value={value} onChange={onChange} />
)

下一步是用 Refract 的withEffects高阶组件包装这个组件,用 ahandler和 anaperture来处理这样的副作用:

import { withEffects } from 'refract-rxjs'
import { debounceTime } from 'rxjs/operators'

const Input = ({ onChange, value }) => (
    <input type="text" value={value} onChange={onChange} />
)

const aperture = () => component =>
    component.observe('value').pipe(debounceTime(300))

const handler = ({ onUpdate }) => value => onUpdate(value)

const DebouncedInput = withEffects(handler)(aperture)(Input)

Anaperture可让您观察组件的props。在这种情况下,观察valueprops是有意义的- 每次value更改时,component.observe('value')流都会获得一个新值。

handler是一个函数,每个值都由光圈的流输出。在这种情况下,去抖动的值会直接传递给名为 的新propsonUpdate

文档中详细解释了孔径和处理程序 -观察 React介绍了孔径,处理效果解释了处理程序。

作为您将如何使用它的示例:

class Search extends React.Component {
    state = { debounced: '', search: '' }

    onSearch = e => this.setState({ search: e.target.value })
    onUpdate = debounced => this.setState({ debounced })

    render() {
        return (
            <div>
                <DebouncedInput
                    type="text"
                    value={this.state.search}
                    onChange={this.onSearch}
                    onUpdate={this.onUpdate}
                />
                <div>debounced value: {debounced}</div>
            </div>
        )
    }
}

使用此代码,文本DebouncedInput将立即显示用户的输入(这是 UX 的理想选择),同时消除调用onUpdate回调的副作用然后将其暴露onUpdate给使用该Search组件的组件将是微不足道