Skip to content

Instantly share code, notes, and snippets.

@fdecampredon
Last active August 29, 2015 14:09
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fdecampredon/9687b27904d1eb25757a to your computer and use it in GitHub Desktop.
Save fdecampredon/9687b27904d1eb25757a to your computer and use it in GitHub Desktop.
possible rx-react events integration
// 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'));
@gaearon
Copy link

gaearon commented Nov 12, 2014

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 in render?).

@gaearon
Copy link

gaearon commented Nov 12, 2014

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.

@spion
Copy link

spion commented Nov 12, 2014

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.

@fdecampredon
Copy link
Author

@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

@gaearon
Copy link

gaearon commented Nov 12, 2014

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.

@fdecampredon
Copy link
Author

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment