peterellisjones / fully-reactive-react-example

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

#React + RxJS: going fully reactive

###React is not reactive

Nowadays React is getting more and more popular. However, despite the name, it is not fully reactive solution. As Andre Staltz says - only rendering is reacitve in React. But can we change that? Can we make a react components more reactive?

###Going reactive in the component

Imagine a simple counter written in plain, old React:

import React from 'react';
import ReactDOM from 'react-dom';

class Main extends React.Component {
  constructor (props) {
    super(props);
    this.state = {count: 0};
  }

  //This is an "API" method of the component
  updateCount (by) {
    this.setState({
      count: this.state.count + by
    });
  }

  render () {
    return (
        <div>
          <button onClick={this.updateCount.bind(this, 1)}>+</button>
          <button onClick={this.updateCount.bind(this, -1)}>-</button>
          <div>count: {this.state.count}</div>
        </div>
    )
  }
}

ReactDOM.render(<Main/>, document.getElementById('app'));

Can you spot referencing a component's API method updateCount(by)? This is proactive approach. The method will be called by the children "components" (in this case - buttons) whenever a click action is triggered upon any of them.

Now what if we could turn the buttons' click events into observables? See the code below:

import React from 'react';
import ReactDOM from 'react-dom';
import Rx from 'rx';

class Main extends React.Component {
  constructor (props) {
    super(props);
    this.state = {count: 0};
  }

  // Click events are now observables! No more proactive approach.
  componentDidMount () {
    const plusBtn = document.getElementById('plus');
    const minusBtn = document.getElementById('minus');

    const plus$ = Rx.Observable.fromEvent(plusBtn, 'click').map(e => 1);
    const minus$ = Rx.Observable.fromEvent(minusBtn, 'click').map(e => -1);

    Rx.Observable.merge(plus$, minus$).scan((acc, n) => acc + n)
      .subscribe(value => this.setState({count: value}));
  }

  render () {
    return (
        <div>
          <button id="plus">+</button>
          <button id="minus">-</button>
          <div>count: {this.state.count}</div>
        </div>
    );
  }
}

ReactDOM.render(<Main/>, document.getElementById('app'));

Take a look at the componentDidMount(). It's a react component's standard lifecycle method called only once, just after the element is added to the DOM. Here we are creating two observable streams of click events (plus$ and minus$) mapped into corresponding values. Then we merge them into single stream. Each time an event is emitted, a scan is called and most-up-to-date state is set upon the component.

No more passing method reference around, no more proactive approach. Here, we went fully reactive.

Additional reading:

About


Languages

Language:JavaScript 88.4%Language:HTML 11.6%