-
-
Save fdecampredon/9687b27904d1eb25757a to your computer and use it in GitHub Desktop.
// in this first option events handlers are just RxJs functor Subject | |
// those subject are passed down to the render function and are manually injected into | |
// the properties of react component | |
var RxReact = require('rx-react'); | |
var React = require('react'); | |
var TodoList = RxReact.createClass({ | |
render(props) { | |
return <ul>{props.items.map(text => <li>{text}</li>)}</ul>; | |
} | |
}); | |
var TodoApp = RxReact.React.createClass({ | |
getInitialState() { | |
return {items: [], text: ''}; | |
}, | |
init(comp) { | |
var change = RxReact.Event.create(); | |
var submit = RxReact.Event.create(); | |
change | |
.map((e) => e.target.value) | |
.subscribe(text => comp.setState({text})); | |
submit | |
.subscribe(e => { | |
e.preventDefault(); | |
var nextItems = comp.state.items.concat([comp.state.text]); | |
var nextText = ''; | |
comp.setState({items: nextItems, text: nextText}); | |
}); | |
return {submit, change}; | |
}, | |
render(props, state, events) { | |
return ( | |
<div> | |
<h3>TODO</h3> | |
<TodoList items={state.items} /> | |
<form onSubmit={events.submit}> | |
<input onChange={events.change} value={state.text} /> | |
<button>{'Add #' + (state.items.length + 1)}</button> | |
</form> | |
</div> | |
); | |
} | |
}); | |
React.render(<TodoApp />, document.getElementById('app')); | |
//vs | |
// in this second option the 'comp' passed to the init function expose a function 'observableFromEvent' | |
// that allows to retrieve an observable sequence from a property name (the event name) and a selector. | |
// the events handlers are automaticly injected in the properties of the react component children | |
var RxReact = require('rx-react'); | |
var React = require('react'); | |
var TodoList = RxReact.createClass({ | |
render(props) { | |
return <ul>{props.items.map(text => <li>{text}</li>)}</ul>; | |
} | |
}); | |
var TodoApp = RxReact.React.createClass({ | |
getInitialState() { | |
return {items: [], text: ''}; | |
}, | |
init(comp) { | |
comp.observableFromEvent('onChange', 'input') | |
.map((e) => e.target.value) | |
.subscribe(text => comp.setState({text})); | |
comp.observableFromEvent('onSubmit', 'form') | |
.subscribe(e => { | |
e.preventDefault(); | |
var nextItems = comp.state.items.concat([comp.state.text]); | |
var nextText = ''; | |
comp.setState({items: nextItems, text: nextText}); | |
}); | |
}, | |
render(props, state) { | |
return ( | |
<div> | |
<h3>TODO</h3> | |
<TodoList items={state.items} /> | |
<form> | |
<input value={state.text} /> | |
<button>{'Add #' + (state.items.length + 1)}</button> | |
</form> | |
</div> | |
); | |
} | |
}); | |
React.render(<TodoApp />, document.getElementById('app')); |
I think explicit quasi-inline handlers are a feature of React, I wouldn't trade this for Backbone-style delegation in some other centralized place. I know React delegates them, but it's an implementation detail.
Right, I also like the first version a lot. Things look very neat in the render function: props
, state
and events
. The whole data flow is very clear and visible.
@gaearon basicly with the second option I just use a tiny selector engine and traverse the tree returned by render to inject properties see :
https://github.com/fdecampredon/rx-react/blob/master/lib/selector.js.
I kinda agree it is a little magic however
Uh, I see. I don't think it fits well with React's explicit flow mantra. Say you have a large render
, then once again you'll have to assign some meaning to class names and use them in event selectors, which makes it much harder to remove dead CSS and easy to break things.
Yup there is another case that bother me also :
RxReact.createClass({
init(comp) {
comp.observableFromEvent('onClick','button').subscribe(....)
},
render(props) {
return (
<div>
<button>button 1</button>
<button onClick={props.onClick}>button2</button> // will be overriden
</div>
}
})
I much prefer the first version. The second one is too magic to my taste (I have no idea how
observableFromEvent
works and what second parameter is—a selector? how would that work with complex hierarchies inrender
?).