Home

Awesome

React Reactive Class

A thin layer between RxJS and React.

npm version

What?

With React Reactive Class, you can create Reactive Components, which subscribe Rx.Observables and re-render themselves.

Counter example

You can compare this example to Counter example of Cycle.js and Counter example of Yolk.

import { Subject, Observable } from 'rx';
import React from 'react';
import ReactDOM from 'react-dom';
import { dom } from 'react-reactive-class';

const { span: Span } = dom;

function Counter () {
  const plusClick$ = new Subject();
  const minusClick$ = new Subject();

  const action$ = Observable.merge(
    plusClick$.map(() => 1),
    minusClick$.map(() => -1)
  );

  const count$ = action$.scan((x, y) => x + y, 0).startWith(0);

  return (
    <div>
      <div>
        <button id="plus" onClick={ (e) => plusClick$.onNext(e) }>+</button>
        <button id="minus" onClick={ (e) => minusClick$.onNext(e) }>-</button>
      </div>
      <div>
        Count: <Span>{ count$ }</Span>
      </div>
    </div>
  )
}

ReactDOM.render(<Counter />, document.getElementById('root'));

Features

Installation

npm install --save react-reactive-class

Usage

Use reactive DOM elements

Example:

import { Subject } from 'rx';
import React from 'react';
import ReactDOM from 'react-dom';
import { dom } from 'react-reactive-class';

const { div: Div, span: Span } = dom;

window.style$ = new Subject();
window.text$ = new Subject();

class App extends React.Component {
  render() {
    console.log('App rendered.');

    return (
      <div>
        <h1>Demo</h1>
        <Div style={window.style$}>Hello</Div>
        <Span>{window.text$}</Span>
      </div>
    );
  }
}

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

// notice that App will not re-render, nice!
window.style$.onNext({color: 'blue'});
window.text$.onNext('Reactive!');
// you can open your console and play around

Use Reactive wrapper

Take full control of component lifecycle.

reactive(ReactClass): ReactClass

Example:

import { Observable } from 'rx';
import React from 'react';
import ReactDOM from 'react-dom';
import { reactive } from 'react-reactive-class';

class Text extends React.Component {
  componentWillMount() {
    console.log('Text will mount.');
  }
  render() {
    console.log('Text rendered.');

    return (
      <div>{this.props.children}</div>
    );
  }
  componentWillUnmount() {
    console.log('Text will unmount.');
  }
}

const ReactiveText = reactive(Text);


const currentTime$ = Observable
  .interval(1000)
  .map(() => new Date().toLocaleString());

ReactDOM.render(
  <ReactiveText>{ currentTime$ }</ReactiveText>,
  document.getElementById('root')
);

Mount/unmount Reactive Component

You can use mount attribute to mount/unmount a component.

// Unmount this component if length of incoming text is 0.
<Span mount={ text$.map(text => text.length) }>
  {text$}
</Span>

Child component constraint

Source must be the only child when using observable as child component.

// This will not work
<Span>
  Hello {name$}, how are you?
</Span>

// This will work
<span>
  Hello <Span>{name$}</Span>, how are you?
</span>

Feedbacks are welcome!

Feel free to ask questions or submit pull requests!

License

The MIT License (MIT)