Introduce to RxJS

  • What is RxJS
  • Why RxJS
  • How to learn RxJS
  • How could I use RxJS in React
  • Introduce some tools articles and videos that can help you to know about RxJS

What is RxJS?

Questions I've asked:

  • "WTH is this? another Lodash?"
  • "What operator do I use for that?"
  • "Why my Observable after concatMap never triggered?"
  • "Why did that Observable die?"
  • "What is this RxJS code I wrote 4 months ago really doing?"

Let's answer a few of these...

Thinking Reactive

Drag and drop for example

For each mousedown on your target, you start listening to mousemoves on the document until a single mouseup on document

Drag and drop

import { fromEvent } from 'rxjs'

const target = document.querySelector('#target')

const targetMouseDown$ =
    fromEvent(target, 'mousedown')

const docMouseMove$ =
    fromEvent(document, 'mousemove')

const docMouseUp$ =
    fromeEvent(document, 'mouseup')

Drag and drop for example

For each mousedown on your target, you start listening to mousemoves on the document until a single mouseup on the document

Drag and drop

import { takeUntil } from 'rxjs/operators'

docMouseMove$.pipe(takeUntil(docMouseUp$))

Drag and drop for example

For each mousedown on your target, you start listening to mousemoves on the document until a single mouseup on the document.

Drag and drop 

const dragDrop$ = targetMouseDown$.pipe(switchMap(
  () => docMouseMove$.pipe(takeUntil(docMouseUp$))
))

Why RxJS?

RxJS is lodash for async

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

How to learn RxJS?

Start from the operator you already know.

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

Learning RxJS

How could I use RxJS in React?

The lifecycle of Observable

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

}

Destroy Observable by takeUntil

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

}

Real world Observables in Our Project

RxJS materials.

  • https://rxviz.com/ help you to understand the behavior of operators
  • https://www.learnrxjs.io/ all operators guide and examples
  • https://www.youtube.com/watch?v=AslncyG8whg&t=1s RxJS and redux-observable introduce from Netflix
  • https://www.youtube.com/watch?v=JCXZhe6KsxQ&t=58s introducing RxJS 6 by Benlesh

Q & A

RxJS

By yinan

RxJS

  • 737