react-spa
react-spa copied to clipboard
Possibility of using omniscientjs?
I see the usage of Immutable-js; I'm wondering if you ever looked into using omniscientjs?
Good suggestion. No, I was not aware of omniscientjs yet, looking into it now.
I noticed here that you are already using omniscientjs with reflux. How did you implement these two together?
Here is an un-tested example; but essentially the same idea I've been using (keep in mind the implicit require()
). This idea was based on this gist.
// cursor.js
var structure = immstruct({});
// store/name.js
var Actions = Reflux.createActions([
'load',
'update'
]);
var nameStore = Reflux.createStore({
init: function() {
this.listenTo(Actions.load, this.load);
this.listenTo(Actions.update, this.update);
},
load: function() {
structure.cursor().update(function(map) {
return map
.set('greeting', 'Welcome')
.set('name', 'bob');
});
},
update: function(newName) {
structure.cursor('name').update(function() {
return newName;
});
// No need to do this: this.trigger(...);
}
});
// components/name.jsx
var mixin = {
componentWillMount: function() {
Actions.load();
}
};
var Name = component(mixin, function ({cursor}) {
var onChange = function(e) {
Actions.update(e.currentTarget.value);
};
return (
<div>
<h1>{cursor.get('greeting')} {cursor.get('name')}!</h1>
<input value={cursor.get('name')} onChange={onChange} />
</div>
);
});
// app.js
function render () {
React.render(
Name(structure.cursor()),
document.body
);
}
render();
// structure.on('swap', render);
// or
structure.on('next-animation-frame', render);
Dataflow is the following:
Initial app state +-----> Cursor +---> UI Component
^ +
| |
| |
+ v
Stores <-----+ Actions
Alright. So, this is pretty much an anti-pattern with regards to isomorphism:
var mixin = {
componentWillMount: function() {
Actions.load();
}
};
Here are some ideas I've been throwing around.
https://gitter.im/omniscientjs/omniscient/archives/2014/12/05
I'm sketching out a thought experiment with hypothetical API. A component would usually
require()
actions/stores (implemented with some flux library) they need. When a store is loaded,init
logic usually execute. Here, at each store'sinit
, we can 'register' a function to a hypothetical CursorManager:CursorManager.on('load', function(structure) { // async/sync stuff... return promise; });
This function would be given a structure, from which you can 'extend' the cursor based on data changes at other areas in the cursor:
structure.once('add', func)
. This is like 'async' code, so we create and return a promise.We execute all functions registered to the
load
hook, and feed each of them with context-specific structure:CursorManager.execute('load', structure | structure.key);
Then when all the promises have resolved, the cursor would be built up by the data stores, then we can run
React.render
at the end step:
CursorManager.done('load', render);
This becomes flexible for isomorphic apps, where you instantiate an empty
structure
, fill with minimal state based on router path and cookies, then let data stores populate the cursor. Afterwards, you can render the UI component.
CursorManager
behaves like an EventEmitter, but it isn't one.
Thanks for your snippet, already gave me some new insights! I'll have to give it some further thought, quite important design decisions to be made here. Regarding omniscient on itself; activity seems to be low at the moment, will have to be sure it's going to be maintained on the long run.
Keep your ideas coming!
No problem! Will keep you posted on my findings. I'll keep an eye on this repo to see what you've come up with.
With regards to omniscient activity, I'd say it's definitely not abandoned. But pretty much on par with reflux's small footprint in its infancy.