1.0.2 • Published 6 years ago

@swyx/reactive-react v1.0.2

Weekly downloads
3
License
MIT
Repository
-
Last release
6 years ago

This is a prototype mockup of a "Reactive" version of React.

In this alternate universe, Observables became a part of Javascript.

We take a minimal implementation of Observables, zen-observable.

The React API we are targeting looks something like this:

function Counters() {
  // demonstrate independent states
  return <div>
    <Counter name="counter a" />
    <Counter name="counter b" />
    </div>
}
function Source() {
  // demonstrate ability to switch sources
  return <SourceSwitching 
          // left={<Counter name="counter b" />} 
          left={<Timer ms={1000}/>} 
          right={<Counter name="counter a" />}
        />
}

class Counter extends Component {
  // demonstrate basic counter
  initialState = 0
  increment = createHandler(e => 1)
  decrement = createHandler(e => -1)
  source($) {
    const source = merge(this.increment.$, this.decrement.$)
    const reducer = (acc, n) => acc + n
    return {source, reducer}
  }
  render(state, stateMap) {
    const {name = "counter"} = this.props
    return <div>
        {name}: {state}
        <button onClick={this.increment}>+</button>
        <button onClick={this.decrement}>-</button>
      </div>
  }
}

class Timer extends Component {
  // demonstrate interval time
  initialState = 0
  source($) {
    const reducer = x => x + 1 // count up
    const source = Interval(this.props.ms) // tick every second
    // source returns an observable
    return scan(source, reducer, 0) // from zero
  }
  render(state, stateMap) {
    return <div> number of seconds elapsed: {state} </div>
  }
}

class Blink extends Component {
  // more fun time demo
  initialState = true
  source($) {
    const reducer = x => !x
    // tick every ms milliseconds
    const source = Interval(this.props.ms) 
    // source can also return an observable
    return scan(source, reducer, true)
  }
  render(state) {
    const style = {display: state ? 'block' : 'none'}
    return <div style={style}>Bring back the blink tag! </div>
  }
}




class CrappyBird extends Component {
  // merging time and coutner
  initialState = {
    input: 50,
    target: 50
  }
  increment = createHandler(e => 3)
  source($) {
    return this.combineReducer({
      input: () => {
        const source = merge(this.increment.$, Interval(200,-1))
        const reducer = (acc, x) => Math.max(0,acc + x)
        return {source, reducer}
      },
      target: () => {
        const source = Interval(200)
        const reducer = (acc) => {
          const int = acc + Math.random() * 8 - 4
          return int - (int-50)/30 // bias toward 50
        }
        return {source, reducer}
      }
    })
  }
  render(state, stateMap) {
    const {input, target} = state
    return <div>
        <button onClick={this.increment}>+</button>
        <h1>Crappy bird</h1>
        <p>Bird: <input type="range" value={input} min={0} max={100} /></p>
        <p>Target: <input type="range" value={Math.round(target)} min={0} max={100} /></p>
      </div>
  }
}

class SourceSwitching extends Component {
  initialState = true
  toggle = createHandler()
  source($) {
    const source = this.toggle.$
    const reducer = x => !x
    return {source, reducer}
  }
  render(state, stateMap) {
    console.log({state})
    return <div>
        <button onClick={this.toggle}>Toggle</button>
        {
          state ? this.props.left : this.props.right
        }
      </div>
  }
}

// taking info from event handler
class Echo extends Component {
  handler = createHandler(e => e.target.value)
  initialState = 'hello world'
  source($) {
    const source = this.handler.$
    const reducer = (acc, n) => n
    return {source, reducer}
  }
  render(state, prevState) {
    return <div>
        <input value={state} onInput={this.handler}/>
        {state}
      </div>
  }
}