omniscientjs / omniscient Goto Github PK
View Code? Open in Web Editor NEWA library providing an abstraction for React components that allows for fast top-down rendering embracing immutable data for js
Home Page: http://omniscientjs.github.io/
A library providing an abstraction for React components that allows for fast top-down rendering embracing immutable data for js
Home Page: http://omniscientjs.github.io/
I am moving along nicely with testing out omniscient in a react stack, but just ran into my first bump. It's pretty late and I haven't looked deep into this yet, but here's the issue.
I have an omniscient component "Articles" that does this:
<List>
{articles.map(article => (
ArticleItem({ article: article.get('data') })
)).toArray()}
</List>
Where ArticleItem
is another omniscient component.
Now, the <List>
component consists of two React components (List
and ListItem
) that generate a nice unordered list for you. List takes an array of items (in this case the omniscient ArticleItem
components), loops over them and passes them to ListItem, which has the following code to display the components:
var children = React.Children.map(this.props.children, child => {
return React.addons.cloneWithProps(child, {style: this.styles.content});
});
The important part being that it is trying to add the "style" property to them along the way, which I use for decorating the child components.
Now, it's outputting everything fine, but I'm not sure how I can access the "style" property I've tried to add to the omniscient component with cloneWithProps
. Again, it's a little late so I may be missing something obvious.
EDIT: To tl;dr, how can I add a property to an omniscient component from a parent React component (preferably still by using cloneWithProps
so I don't have to customize my React component just for omniscient)?
i get this error from immutable.js:617
iterable.length has been deprecated, use iterable.size or iterable.count(). This warning will become a silent error in a future version. Error
at KeyedCursor.Object.defineProperty.get (https://localhost:8009/main.bundle.js:28476:20)
at isBuffer (https://localhost:8009/main.bundle.js:10901:47)
at objEquiv (https://localhost:8009/main.bundle.js:10925:8)
at module.exports (https://localhost:8009/main.bundle.js:10892:13)
at objEquiv (https://localhost:8009/main.bundle.js:10957:11)
at module.exports (https://localhost:8009/main.bundle.js:10892:13)
at hasChangedProperties (https://localhost:8009/main.bundle.js:8189:11)
at shouldComponentUpdate (https://localhost:8009/main.bundle.js:8140:8)
at ReactCompositeComponentMixin.performUpdateIfNecessary (https://localhost:8009/main.bundle.js:16022:13)
at runBatchedUpdates (https://localhost:8009/main.bundle.js:22219:18)
my deps:
"omniscient": "~2.0.1",
"immstruct": "~1.0.1"
Some tasks involved with the documentation and the new site:
Suggestions for more? Tutorials?
Tutorials point to the dead link:
I think this may be a better default, rather than deref()
ing:
module.exports.isEqualCursor = function isEqualCursor (a, b) { return Immutability.is(a, b); };
This would create dependency on Immutability
though.
I find it confusing that if I do App(cursor)
my App component needs to grab props.cursor
instead of just receiving a cursor, while if I do App({ x: xCursor, y: yCursor })
I can just get cursors as x
& y
. I think it would be a lot better if omniscient would unbox cursor if that's what was passed to a component.
I'd be like to get omniscient to a point where it can be used with vtree+ vdom instead of react for few reasons:
Now that there are new React.js 0.13 versions, we should relax the peer dependency in package.json so they can be used. I'm not sure the easiest syntax for doing this (rather than listing a bunch of beta versions).
npm view react
'0.13.0-beta.1': '2015-01-28T05:19:01.230Z',
'0.13.0-beta.2': '2015-02-14T02:37:43.316Z',
'0.13.0-rc1': '2015-02-22T21:36:01.461Z' },
Currently package.json has
"peerDependencies": {
"react": ">=0.12.0 || 0.13.0-beta.1"
},
so npm won't let me use the latest React RC without hacking it.
Create a relative term of reference for performance to be able to see if performance is improved or not on code changes.
First, consider this being not an issue or bug with Omniscient but more an implementation question.
I am thinking about how Omniscient could fit into the picture of isomorphic rendering which aims to make it possible to render the apps page/routes not only on the client but server too.
It seems a challenge would be to
a) keep the state either synced on both, the server and client or
b) maybe just have it on the server and query it somehow from the client side?
How could an implementation look like?
In case a, would it make sense to open two Omniscient instances, one on the client, one on the server? Could they communicate/sync somehow?
Or in case b, could I connect client requests/updates to an Omniscient server instance, via websocket for example?
I'm not sure, can I use Omniscient components as handler for react-router the same as if I would use normal React components?
I tried this:
var React = require('react');
var Router = require('react-router');
var { Route, DefaultRoute, RouteHandler, Link } = Router;
var Comp-a = require('./comp-a').jsx;
var Comp-b = require('./comp-b').jsx;
var App = React.createClass({
render: function () {
return (
<div>
<ul>
<li><Link to="comp-a">Comp-a</Link></li>
<li><Link to="comp-b">Comp-b</Link></li>
</ul>
<RouteHandler/>
</div>
);
}
});
var Home = React.createClass({
render: function () {
return <h1>Home</h1>;
}
});
var routes = (
<Route handler={App}>
<DefaultRoute handler={Home}/>
<Route name="clicks" handler={Comp-a}/>
<Route name="arno" handler={Comp-b}/>
</Route>
);
Router.run(routes, function (Handler) {
React.render(<Handler/>, document.body);
});
But clicking on the links, I get errors such as:
Uncaught TypeError: Cannot read property 'deref' of undefined
and
Uncaught TypeError: Cannot read property 'unmountComponent' of undefined
https://github.com/swannodette/om/wiki/Advanced-Tutorial#reference-cursors
Supporting these would prevent the long chain of passing props (or in omniscient's case, cursors) down long component trees. It would be really cool to have something like these. Morearty.js has something like this.
Wondering about your thoughts here.
I was initially sold on omniscient when I read the following post: http://open.bekk.no/easier-reasoning-with-unidirectional-dataflow-and-immutable-data
I think this is much better intro to omniscient than from the official overview/docs.
I think that this post should be transferred to omniscientjs's site/repo, probably as a separate page/markdown file.
What do you think @mikaelbr?
Hello. I'm creating an issue for the Immutable 3.0 upgrade. Hopefully you don't mind- I'm not in a rush but would like to have this ticket to be able to track/have notice of the change-over.
This is slightly different issue than #41 - I don't want to store cursors in state, just immutable objects instead of mutable ones.
Unfortunately, because somewhere in lodash's isEqual method, it uses the "length" property, which is going to be deprecated in a future version of Immutable.JS https://github.com/facebook/immutable-js/wiki/Upgrading-to-Immutable-v3#size-from-length, it throws a warning anytime the function is called with Immutable.JS objects.
I'm not sure what exactly can be done about this, off the top of my head. But I wanted to flag it as an issue and put it up for discussion, as I feel like it's kind of important that we support putting immutable objects in state and props.
P.S.: I'm of course aware that I could override shouldComponentUpdate to make it so that, if I'm consistent in using all Immutable values for any deep structures in my state/props, i could just do a shallow equal (or just use PureRenderMixin, I suppose). I just think it'd be nice to include support in this library seeing as we're encouraging the use of immutable data structures throughout the rest of the application.
Sometimes (e.g. when namespacing), cursors are checked with a isEqual check. This needs to be working better. At least show a warning and clear the usage. Preferably, it should just work, but it depends on performance and complexity.
Hi,
DOn't know if it is the place to ask this but may be you had this issue ?
I am trying to use omniscient using watchify and browserify with gulp.
React is loaded twice and the browser give me the following error:
"Uncaught Error: Invariant Violation: renderComponent(): Invalid component descriptor. This may be caused by unintentionally loading two independent copies of React. "
My gulpfile.js task is like this:
gulp.task('browserify', function() {
var bundler = watchify(browserify('./js/app.coffee', watchify.args));
bundler.transform(coffeeify);
bundler.on('update', rebundle);
function rebundle() {
return bundler.bundle()
.on('error', gutil.log.bind(gutil, 'Browserify Error'))
.pipe(source('bundle.js'))
.pipe(gulp.dest('./js'));
}
});
I think that the problem can come from the fact that as i use React = require('react') in my app.js file and that omniscient is also using this it is loaded twice.
Does someone already had this issue ?
Many thanks,
Samuel
I've been diving into (and loving) this project for the last week. I was just wondering what your thoughts were towards React 0.13 and dealing with generic classes. Would is be possible to return the custom class from the internals instead of returning the result of React.createElement
? I ask because it would cleanup the jsx usage. The other option I was thinking about was making it a config option now that withDefaults
is an available API.
Anyhow, keep up the excellent work.
By @dashed
Thinking on this some more, I think there can be more done with shouldComponentUpdate so that the comparison process is done uniformly on both props and state. At the moment, state just gets the isEqual treatment.
Here's an example of putting a cursor in component's state:
var structure = immstruct({turtles: []}); var TurtlesComponent = React.createClass({ componentWillMount: function() { this.setState({turtlesCursor: structure.cursor()} structure.on('swap', () => this.setState({turtlesCursor: structure.cursor()})); }, onAddButtonClick: function(e) { this.state.turtlesCursor.updateIn('turtles', (turtles) => turtles.push(e.target.turtle) ); }, renderTurtleCount: function() { return <div>{this.state.turtlesCursor.deref().size}</div>; // or pass own sub-cursor to a child component... } });
I have a question about updating a cursor.
omniscient
structure.cursor('name').update(function () {
return 'Doctor';
});
vs Immstruct
// Remember: Cursor is immutable. Update cursor.
var cursor = structure.cursor('name').update(function (x) {
return x + 1;
});
when a cursor is immutable, why is the omniscient version working? I try to understand this, because at some point, update('name', ... ) is not working for me.
Just wondering your thoughts on this pattern. Say we have an event handler in a component that then wants to update it's cursor.
It seems you have two options.
To me you don't get the niceties of react's this.state
. With this.state
your mixins can access state the same as non-mixins (stuff in render, etc). With this setup it seems I have to make a choice between two ways, and neither is compatable.
Wondering what your thoughts are. I like the functional style of avoiding this
in general, but it does seem ugly have to do onEven={this.eventHandler.bind(this, cursor)}
. I'd like to just have the handlers defined within render(), but that seems expensive, and also not very composable when the need to share them comes up.
Hi. First off. Great library.
I've forked the router example and altered it to demonstrate a problem I'm having
https://github.com/dweave/react-router-omniscient-example
I'm wondering if anyone has any suggestions on handling this situation. As you see, when there is not a new cursor provided, the components do not rerender. (I'm guessing this is because of how shouldComponentUpdate is implemented). I realize this isn't a bug, but it seems like a tricky problem to solve especially when you have any kind of complex nesting of routes.
Anyone have any suggestions? I realize simply implementing a new shouldComponentUpdate returning true would work for certain views in particular, but this would detract from a lot of the value of omnsicient + immstruct.
Dan
React v0.12 was released! Both React functions that are used in Omniscient were deprecated. Is an update to Omniscient planned?
As with passing cursor, a non-JSX component should support passing in single immutable value.
React.render(Component(myImmutableStructure));
Help, I'm stuck!
When I npm install
omniscient, there are weird characters in the distributed file:
function pickStaticMixins (mixins) {
var filtered = mixins.filter(function (obj)Â {
return !!obj.statics;
});
Then I get unexpected identifier errors when I run.
This is vaguely related to #67, as I was trying to find a solution for a child to cause side on a state that does is not part of state that affects it's output. In other words originally, I would pass parent components state along with a child state so that child could render itself, but then make changes to parent like remove itself for example. The problem with that approach was that any time parent would change all it's children would be re-triggered since parent state was passed to each one.
So then I considered using CSP channels to do communication, but then problem with those has being that one needs to create & subscribe to them and that means you no longer can use plain component(render)
style, not to mention that it seems overkill for just removing a child from it's parent.
I think #67 provides a simple solution, although it does kind of require wrapping actual operational functions in event handlers to be passed down to children. In that regard just passing down a parent cursors seems more appealing.
Lately I have being thinking that if cursors just a had a way to access it's parent that could provide pretty elegant solution for children to cause changes upwards.
Is there a plan to support JSX, or is there a reason for the incompatible syntax?
After using omniscient for some time now, we often runt into scenario like this one:
https://github.com/mozilla/browser.html/blob/master/src/browser/browser.js#L118
Here is a simplified version of it that is vaguely based on code from the tutorial (although
here component takes two cursors one for libs
and the other for search
):
var Matches = component('Matches', ({libs, search}) => {
// Create a query out of the cursor
var q = makeQuery(search);
// Get all javascript projects that matches the query
var matches = libs.map(function (lib) {
return q.test(lib.get('title')) || q.test(lib.get('url'));
});
// Present the matches
return React.DOM.ul({}, matches.toArray().map(function (lib, i) {
return Match('match-' + lib.get('title'), lib);
}));
});
Let's assume that unlike in original example search
here is a cursor to some kind of object, let's say {input: "*.js"}
rather than just string.
It would be really nice if makeQuery
could be defined as follows:
const {cached} = require('omniscient');
const makeQuery = cached(input => new RegExp(input.replace(/\*/, '[\\s\\S]*')));
Where implementation of cached
could be something along this lines:
const {shouldComponentUpdate} = require('omniscient');
const cached = f => {
const g = input =>
shouldComponentUpdate(input, g.input) ? g.return = f(input) : g.return
return g
}
Which can be thought as a generalisation of component
if we ignore all the react specifics it currently
does.
Implement something like withSettings
.
It would still be, for 95% of the cases:
var component = require('omniscient');
But if you want to override any methods, instead of:
var component = require('omniscient');
component.isEqual = function () { ... }
you do:
var component = require('omniscient').withSettings({
isEqual: function () { ... }
});
Much cleaner API, in my mind. Also less error prone.
First add deprecation notice on existing API, but remove existing API at next major release (v3.0.0
).
I think the global override should be more of a user choice/implementation, and it's just to brittle. Would't want Omniscient to rely on a major magic state that you have defined in one of your modules. That's essentially a huge side-effect.
A better solution, by my opinion, would be to make a defaults module your own:
// defaultOmniscient.js
module.exports = require('omniscient').withSettings({
// my defaults
});
// some module:
var component = require('./defaultOmniscient');
// ...
I think this is a much more robust and "reason-able" approach.
I came across this error when using omniscient.
Download the React DevTools for a better development experience: http://fb.me/react-devtools
app.js:15167 iterable.length has been deprecated, use iterable.size or iterable.count(). This warning will become a silent error in a future version. Error
at IndexedCursor.Object.defineProperty.get (http://dashed.github.io/omniscientjs-sandbox/js/app.js:15162:20)
at isBuffer (http://dashed.github.io/omniscientjs-sandbox/js/app.js:14466:47)
at objEquiv (http://dashed.github.io/omniscientjs-sandbox/js/app.js:14490:8)
at module.exports (http://dashed.github.io/omniscientjs-sandbox/js/app.js:14457:13)
at objEquiv (http://dashed.github.io/omniscientjs-sandbox/js/app.js:14522:11)
at module.exports (http://dashed.github.io/omniscientjs-sandbox/js/app.js:14457:13)
at objEquiv (http://dashed.github.io/omniscientjs-sandbox/js/app.js:14522:11)
at module.exports (http://dashed.github.io/omniscientjs-sandbox/js/app.js:14457:13)
at objEquiv (http://dashed.github.io/omniscientjs-sandbox/js/app.js:14522:11)
at module.exports (http://dashed.github.io/omniscientjs-sandbox/js/app.js:14457:13)
The stacktrace seem to point to node-deep-equal via immstruct.
This happens when I do this:
React.render(<Panel><List.jsx cursor={structure.cursor('items')} /></Panel>, document.getElementById('boop'));
vs.
React.render(<List.jsx cursor={structure.cursor('items')} />, document.getElementById('boop2'));
I use the following component that just wrap this.props.children
: https://github.com/Dashed/omniscientjs-sandbox/blob/gh-pages/client/components/panel.jsx
Here's a simple project that can reproduce the warning: https://github.com/Dashed/omniscientjs-sandbox
Demo: http://dashed.github.io/omniscientjs-sandbox/ (see console when deleting items)
Playing with this library, I get these: Warning: This JSX uses a plain function. Only React components are valid in React's JSX transform.
Currently the way to use omniscient with require.js requires boilerlpate:
require(["react"], React => {
window.React = React;
require(["omniscient"], component => {
// your code here
});
});
This is unfortunate, I believe that could be avoided either by updating UMD wrapper generated or by generating different dists one for AMD one for the current case.
Would be nice to have an example on how to properly test a component.
At least I couldnt find one in the other example repos :)
Thanks
This (at least until react adds support for web workers) will depends on #49. I have in the past successfully used vtree + vdom in the web worker thread in prototype that completely followed Elm-html and it's todo-mvc implementation. You can see it running all of the app code in web worker in action and an implementation that depends on bindings for vtree + vdom .
@DanBunea posted issue at omniscientjs/omniscientjs.github.io#4:
Hi,
It seems to me that there are lots of great things in your framework (immutables with cursors and one direction data flow over react). I am wondering whether there is a possibility to get a proper dist file not requiring me to use require/browserify like react or immutablejs have in their git (eg: https://github.com/facebook/immutable-js/tree/master/dist). We're looking for a very functional framework, that we can later combine with bacon.js for complex events and it seems omniscient might be the answer.
Thank you,
DanPS My team and I are unfamiliar with node and trying to put all the pieces together with browserify/derequeire generated an very big bundle file (570k), with lots of issues.
Content deleted -> double issue posting, were not able to delete it entirely on my own, sorry.
Noting this... I'm moving away from omniscient just because it adds a bit to learning my stack, and you end up creating omniscient specific components. Anyway, just wanted to leave that feedback that I do love the idea behind it, and I want to keep using the shouldComponentUpdate part.
I'll put together a pull request for this eventually so people can require just the mixins for their own use, just wanted to open this up as a reminder to myself.
I think one thing that's a bit odd with omniscient is the change of statics from React. I just ran into something using an external library that wants you to set something on React statics in order to work with it. Unfortunately omniscient doesn't actually let you set statics, and further the statics name is already in use by omniscient for something else.
Just wondering your thoughts on this.
Could you provide an example of how to load data via an ajax call? I can't figure out how to trigger a re-render / swap from outside of the component hierarchy. I was planning on creating some methods that can manipulate the state without belonging to a component.
var structure = immstruct({ greeting: 'Welcome', guest: { name: '' }, objectives: [{name:"test"}] });
function render () {
React.renderComponent(
App(structure.cursor()),
document.getElementById('app'));
}
render();
structure.on('swap', render);
// now how would I update something from here?
// this doesn't work
structure.cursor().get('greeting').update(() => "Hello")
When I first looked into omniscient I read following guide http://omniscientjs.github.io/guide.html#omniscient-react-js which unfortunately is invalid at least with a most recent version of immutable.js
I think we should:
During the refactoring, it seems like isCursor
was removed from the exported object. Since it is able to override isCursor
in the new implementation, I think it would be a good idea to attach it to the ComponentCreator.
I am working on a library that needs to know if props
is a cursor, and would like to be able to use the custom defined isCursor
to do it.
It looks to me like the way omniscient worked before refactor is that it took a cursor given as props and attached it to props.cursor
, but now it takes a cursor as props
directly, attaches it to a hidden property and then uses it inside the render method. Would it make sense to take a cursor that was passed in as props.cursor
and do the same thing as if the cursor is passed directly as props
? This would make it easier to work with statics and cursors.
Should we change logo? Maybe we should look into having a prettier, cleaner logo. Maybe something with color (but could also work in black and white).
Inspiration suggestion from @dashed : http://thenounproject.com/term/eye-of-providence/43465/
One of the biggest challenges I found with omniscient, is to use it in a referentially transparent way without destroying performance. Let me elaborate exactly what I mean:
The way we use omniscient is without this
or mixins, as both imply mutable this.props
and there for are not referentially transparent & there for not much better than use of plain react.
Using omniscient this way poses a challenge, of how could children perform a task that changes state larger than what they render. Here is a practical example:
const Tab = Component({items, item}) => DOM.div({
className: 'tab'
/* ... */
}, [
DOM.button({
onClick: event => items.remove(item)
})
])
const TabDeck = Component(items => DOM.div({
className: 'tabs'
/* .... */
}, items.map(item => Tab({items, item}));
The problem with that is that any change to any tab will re-trigger Tab
component for every tab & generate virtual DOM that will be mostly equal, but still it's linear.
The other solution one could think of is:
const Tab = Component({onRemove, item}) => DOM.div({
className: 'tab'
/* ... */
}, [
DOM.button({onClick: onRemove})
])
const TabDeck = Component(items => DOM.div({
className: 'tabs'
/* .... */
}, items.map(item => Tab({item, onRemove: () => items.remove(item)}));
But unfortunately it has exact same issue. Although I believe we could make some changes to omniscient to fix the later case.
Could be possible for you to add an example of a debounce situation, but using omniscient instead of plain react code?
I'm trying to create a simple search component with a debounce of 300ms before fires the updates on the immstruct, and seems I'm losing something in the middle.
Thanks for your time 😄
I want to bring this to your attention: https://github.com/dustingetz/react-cursor/blob/master/src/ImmutableOptimizations.js
Unsure if it's any useful, but they have configurable keys as a whitelist for reference check (===) instead of deep equal. Not only that, but they also have ignore keys which may be added to isNotIgnorable ruleset.
Then as an idea:
var shouldUpdate = require('omniscient/shouldupdate'); shouldupdate; // default shouldComponentUpdate shouldComponentUpdate({ deepEqual: _.isEqual, objectFilter: _.filter, ... });Can we be able to change filterKeyValue and deepEqual? This is probably useful if we want to use our favourite implementations of object-filter or deep-equal; usually using libraries suitable for particular environment (e.g. browser/node.js).
Hey guys. I get this warning when I store a cursor in the component's state:
onEdit: function onEdit () { this.setState({ editing: true, value: this.props.cursor }); },This warning seem to occur at the following:
... at isEqualState (http://localhost:35150/js/app.js:648:77) at shouldComponentUpdate (http://localhost:35150/js/app.js:732:9) ...Unsure if it's an anti-pattern to be storing cursors in state. But I'm doing it so I can revert changes, such as when the user presses the Cancel button.
Hi guys, I'm getting omniscient to work with react-router (which is excellent, btw).
https://gist.github.com/seanhess/be7b965ddacfdaefe84e
So the page function lets you define a "page" which is a little react component that interfaces with react-router.
What do you think of the interface? Do you want a PR or should I publish this somewhere else?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.