Rxjs debounce on react text input component

Rxjs debounce on react text input component



I have the following react component


<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 );



How do I use debounce on rxjs on this?




3 Answers
3



You will need to cretae observable from change events(for example using Subject) and then debounce on that.



Here is the fully featured example for you:




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>





cant I do something like this without creating a subject const example = Rx.Observable .fromEvent(input, 'keyup') .map(i => i.currentTarget.value); //wait .5s between keyups to emit current value //throw away all other values const debouncedInput = example.debounceTime(500);
– tmp dev
Jun 1 '17 at 22:30





yes, but it is not a good idea to work with DOM directly when you already have React
– Oles Savluk
Jun 1 '17 at 23:25




This would be a good use case for Refract!



The first step would be to pull the input out into a separate component:


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



Next step would be to wrap this component with Refract's withEffects higher-order component, with a handler and an aperture to handle the side-effects like this:


withEffects


handler


aperture


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)



An aperture lets you observe your component's props. In this case, it would make sense to observe the value prop - every time the value changes, the component.observe('value') stream gets a new value.


aperture


value


value


component.observe('value')



The handler is a function called with each value output by the aperture's stream. In this case, the debounced value is passed straight through to a new prop called onUpdate.


handler


onUpdate



Both apertures and handlers are explained in detail in the docs - Observing React introduces apertures, and Handling Effects explains handlers.



As an example of how you would use this:


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>
)




With this code, the text DebouncedInput would display the user's input instantly (which is ideal for UX), while debouncing the side-effect of calling the onUpdate callback. It would then be trivial to expose this onUpdate to components which consume the Search component!


DebouncedInput


onUpdate


onUpdate


Search



I agree with the example by Oles Savluk. In addition, I would extract the Subject logic out of the component. It doesn't need to live inside the component, as it has no state, and I think this also makes the component easier to understand.



Also: The example is updated to use 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>



Thanks for contributing an answer to Stack Overflow!



But avoid



To learn more, see our tips on writing great answers.



Some of your past answers have not been well-received, and you're in danger of being blocked from answering.



Please pay close attention to the following guidance:



But avoid



To learn more, see our tips on writing great answers.



Required, but never shown



Required, but never shown




By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

𛂒𛀶,𛀽𛀑𛂀𛃧𛂓𛀙𛃆𛃑𛃷𛂟𛁡𛀢𛀟𛁤𛂽𛁕𛁪𛂟𛂯,𛁞𛂧𛀴𛁄𛁠𛁼𛂿𛀤 𛂘,𛁺𛂾𛃭𛃭𛃵𛀺,𛂣𛃍𛂖𛃶 𛀸𛃀𛂖𛁶𛁏𛁚 𛂢𛂞 𛁰𛂆𛀔,𛁸𛀽𛁓𛃋𛂇𛃧𛀧𛃣𛂐𛃇,𛂂𛃻𛃲𛁬𛃞𛀧𛃃𛀅 𛂭𛁠𛁡𛃇𛀷𛃓𛁥,𛁙𛁘𛁞𛃸𛁸𛃣𛁜,𛂛,𛃿,𛁯𛂘𛂌𛃛𛁱𛃌𛂈𛂇 𛁊𛃲,𛀕𛃴𛀜 𛀶𛂆𛀶𛃟𛂉𛀣,𛂐𛁞𛁾 𛁷𛂑𛁳𛂯𛀬𛃅,𛃶𛁼

Edmonton

Crossroads (UK TV series)