For each mousedown on your target, you start listening to mousemoves on the document until a single mouseup on document
import { fromEvent } from 'rxjs'
const target = document.querySelector('#target')
const targetMouseDown$ =
fromEvent(target, 'mousedown')
const docMouseMove$ =
fromEvent(document, 'mousemove')
const docMouseUp$ =
fromeEvent(document, 'mouseup')
For each mousedown on your target, you start listening to mousemoves on the document until a single mouseup on the document
import { takeUntil } from 'rxjs/operators'
docMouseMove$.pipe(takeUntil(docMouseUp$))
For each mousedown on your target, you start listening to mousemoves on the document until a single mouseup on the document.
const dragDrop$ = targetMouseDown$.pipe(switchMap(
() => docMouseMove$.pipe(takeUntil(docMouseUp$))
))
Actually RxJS is not for state management, it's a big mistake by some developers who were not familiar with RxJS.
We are still finding a best practice to compose our frontend techs, but it's okay to use RxJS in imperative way in your React Component.
Observable | Promise | |
---|---|---|
Task type | sync or async | async |
Scheduler | Execute on subscribe | Execute immediately |
Value | Empty or single or multiple | Single |
import { Observable } from 'rxjs'
import { map } from 'rxjs/operators'
const a$ = new Observable(observer => {
observer.next(1)
observer.complete()
})
const b$ = a$.pipe(
map(x => x + 1)
)
b$.subscribe((result) => {
console.log(result) // 2
})
Write your imperative codes in subscribe
const questions$ = query(this.questionQuery, queryArgs)
.subscribe(({ data, loading }) => {
// imperative codes
if (loading) {
this.setState({ loading: true })
} else {
this.setState({ questions: data.questions })
}
})
class SomeComponent extends React.PureComponent {
state = {
question: null
}
get questionQuery () {
return gql`
${this.props.questionId}
whateverquery
`
}
clickGetQuestion$ = new Subject()
question$ = this.clickGetQuestion$.pipe( // setup Observables
skipWhile(() => !!this.state.question),
exhaustMap(() => rxFetch.query(this.questionQuery)),
tap((response) => {
this.setState({ question: response.data })
})
)
onClickGetQuestion = () => {
this.clickGetQuestion$.next() // push data into question$
}
componentDidMount() {
this.subscription = this.question$.subscribe() // start Observables in componentDidMount
}
componentWillUnmount() {
if (this.subscription) this.subscription.unsubscribe() // destroy Subscriptions in componentWillUnmount
this.clickGetQuestion$.complete()
}
render() {
return (
<div>
<button onClick={this.onClickGetQuestion}>Get question</button>
{ this.state.question.title }
</div>
)
}
}
class SomeComponent extends React.PureComponent {
state = {
question: null
}
get questionQuery () {
return gql`
${this.props.questionId}
whateverquery
`
}
clickGetQuestion$ = new Subject()
destroy$ = new Subject()
question$ = this.clickGetQuestion$.pipe( // setup Observables
skipWhile(() => !!this.state.question),
exhaustMap(() => rxFetch.query(this.questionQuery)),
takeUntil(this.destroy$), // destroyed once the this.destroy$ has value
tap((response) => {
this.setState({ question: response.data })
})
)
onClickGetQuestion = () => {
this.clickGetQuestion$.next() // push data into question$
}
componentDidMount() {
this.subscription = this.question$.subscribe() // start Observables in componentDidMount
}
componentWillUnmount() {
this.destroy$.next()
this.destroy$.complete()
this.clickGetQuestion$.complete()
}
render() {
return (
<div>
<button onClick={this.onClickGetQuestion}>Get question</button>
{ this.state.question.title }
</div>
)
}
}