Rxjs反应文本输入组件

时间:2017-06-01 06:04:48

标签: reactjs rxjs

我有以下反应组件

<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 个答案:

答案 0 :(得分:15)

你需要从变化事件(例如使用主题)中创造出可观察性,然后对其进行去抖动。

以下是适合您的全功能示例:

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>

答案 1 :(得分:1)

这将是Refract的好用例!

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

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

下一步是用Refract的withEffects高阶组件包装该组件,并使用handleraperture处理这样的副作用:

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)

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

handler是一个由光圈流输出的每个值调用的函数。在这种情况下,去抖动的值会直接传递到名为onUpdate的新道具。

文档中详细说明了光圈和处理程序-Observing React介绍了光圈,Handling Effects说明了处理程序。

作为如何使用此示例:

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组件的组件就变得微不足道了!

答案 2 :(得分:0)

我同意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>