【问题标题】:How to debounce user input in reactjs using rxjs如何使用 rxjs 在 reactjs 中消除用户输入的抖动
【发布时间】:2016-05-19 07:05:42
【问题描述】:

我的问题可能是一个微不足道的问题,但到目前为止我无法找到答案。

如何在用户输入时延迟(去抖动)React 中的更新状态,以避免不必要的更新?

拥有<input onChange={this.onChange} .../>,如何将 onChange 事件与 rxjs 绑定?我应该尝试使这个输入可观察,还是应该使用 FromEventPattern?

在这两种情况下,我都不知道如何将 React 事件与 rxjs 绑定。 第二个问题是用户在去抖动期间是否会看到任何输入变化?

【问题讨论】:

    标签: reactjs rxjs


    【解决方案1】:

    解决方案 #1

    使用主题:Fiddle

    const state = new Rx.Subject()
                  .debounceTime(1000)
                  .scan((acc) => {
                    return ++acc
                  }, 0).do(::console.log)
    
    
    const handler = (e) => {        
      state.next(e)
    }
    
    state.startWith(0).subscribe((clicks) => {
      ReactDOM.render(<button onClick={handler}>Clicked {clicks}</button>, document.querySelector('#app')) 
    })
    

    解决方案 #2

    使用 rxjs 的 fromEvent:Fiddle

    // Intial render so element exists in dom (there is probably a better pattern)
    ReactDOM.render( <button id='clickMe'>Click Me</button>, document.querySelector('#app')) 
    
    const clicks = Rx.Observable
                    .fromEvent(document.getElementById('clickMe'), 'click')
                    .do(::console.log)
                    .debounceTime(1000)
                    .scan((acc) => {
                      return ++acc
                    }, 0)
    
    clicks.subscribe((clicks) => {
      ReactDOM.render( <button id='clickMe'>Click Me {clicks}</button>, document.querySelector('#app')) 
    })
    

    解决方案 #3

    注意:高度实验性,只是我为了好玩而尝试做的事情。

    这更适用于基于动作的架构,在这种架构中,您的动作会改变您的状态(通量)。这是一个完全独立的处理程序。它与自定义运算符“fromEventArgs”一起使用:Fiddle(查看控制台)

    const handler = (e) => {        
      Rx.Observable
        .fromEventArgs(e, 'UniqueKey') 
        .debounceTime(1000)        
        .subscribe(x => console.log('Send an action', x))
    }
    

    【讨论】:

    • 谢谢,使用 Subject 似乎最适合我,但是我只需要根据我的需要订阅和处理输入而不是扫描(“折叠”语义除外)。
    • 很高兴听到。如果您觉得我的回答不错,请采纳。
    • 我似乎无法让解决方案 #2 与新的 RXJS 一起使用,任何更新答案的机会。这非常有用,尽管已经过时了。
    【解决方案2】:

    基于 omerts 命题,(尤其是解决方案 #1)这是我的最终代码

    input: Rx.Subject<any>;
    
    constuctor(...){
       this.input = new Rx.Subject();
       this.input.debounce(1000).subscribe(this.processInput);
    }
    
    handleChange = event => {
       event.persist();
       this.input.onNext(event);
    
        };
    
    processInput = x => {
       // invoke redux/flux action to update the state
    }
    
    render(){
       ...
       <input onChange={this.handleChange} ... />
       ...
    }
    

    【讨论】:

      【解决方案3】:

      试试这样:

      class MyScene extends React.Component {
      
          constructor(props) {
              var onChangeTextObservable = Rx.Observable.fromEventPattern(
                 (handler) => {this.onChangeText = handler}
              );
              onChangeTextObservable.subscribe(x => console.log(x));
          }
      
          render() {
             return (
                <TextInput onChangeText={this.onChangeText}>
             )
          }
      
      }
      

      【讨论】:

        【解决方案4】:

        我一直在回答这个问题,但我更喜欢this solution from another one

        为简单起见,复制如下。请为原作点赞。


        您需要从更改事件中创建 observable(例如 使用 Subject) 然后去抖动。

        这是为您准备的全功能示例:

        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>

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-04-10
          • 2016-04-03
          • 2021-09-08
          • 2021-02-20
          • 1970-01-01
          • 2015-01-22
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多