Why doesn't Redux just push the new state to listeners (as a parameter) like many callbacks do?
for (var i = 0; i < listeners.length; i++) {
listeners[i](currentState)
}
So we could...
store.subscribe(state => {
// ...just use it here...
})
...instead of having to call
store.subscribe(() => {
store.getState() // ?
})
Okay, it looks like this has been suggested numerous times in Redux's issue tracker on GitHub.
Here is what the devs have said about it:
#303 (Jul 27, 2016) "subscribe [is] a low level API." — gaearon, the project founder
#1514 (Mar 11) "In any case, having just the new state is not very useful. You’ll probably want the previous state too. And not just the previous state—probably a specific part you care about. At which point you might as well write your own helper to do this." — gaearon
#1832 (Jun 27) "The short version is that Redux just provides the simplest API possible."
And that's just a few of them. Tons of people have asked this question.
I would write a TL;DR here, but I don't feel like it. So please do read anyway. :-)
Related
Upgrading AngleSharp from 0.9.6 to 0.9.9 I have this line of code no longer compiling:
return configuration.With(LoaderService(new[] { requester }));
It complains that LoaderService does not exist in the current context. So what happened to LoaderService? Is there a replacement? Does it still exist but just somewhere else?
Good question. Sorry for being late to the party, but even though you may have solved your problem someone else is having a hard time figuring it out.
LoaderService was essentially just a helper to create a loader. But having a service for anything creating a little thing would be overkill and not scale much. Also AngleSharp.Core would need to define all these. So, instead a generic mechanism was introduced, which allows registering such "creator services" via Func<IBrowsingContext, TService>.
However, to solve your piece of code I guess the following line would do the trick:
return configuration.WithDefaultLoader(requesters: requester);
This registers the default loader creator services (one for documents, one for resources inside documents) with the default options (options involve some middleware etc.).
Under the hood (besides some other things) the following is happening:
// just one example, config.Filter is created based on the passed in options
return configuration.With<IDocumentLoader>(ctx => new DocumentLoader(ctx, config.Filter));
I currently have my publications stored in /server/publications.js. I would like to store my client-side subscriptions in a central file too, like in /client/subscriptions.js. Is this a good design decision or are there more cons than pros? Thanks
There are three main places you can subscribe to a Meteor collection.
Globally
In this approach, you create subscriptions in a file somewhere on the client. Like your example, subscriptions.js is what most people name it. As long as it's in the client folder, it's fine.
Meteor.subscribe("posts");
Good candidates for this are collections that you will play around with on all or most of your templates. A friends list similar to Facebook, a feed of some kind.
Router
If you're using something like iron-router or flow-router, you can subscribe to collections based on the URL. I prefer this approach the most. It's flexible, but not too taxing on performance. For example:
// Inside lib/router.js
FlowRouter.route('/blog/:postId', {
subscriptions: function(params) {
this.register('myPost', Meteor.subscribe('blogPost', params.postId));
}
});
Now you can access the data you need using myPost. Very neat, and you can subscribe to as many things as you need.
Template
This is the most flexible of all and the most taxing if you have multiple templates. Honestly, just avoid this approach because it's way too much work. 90% of the time I find myself using Router subscriptions.
Template.posts.onCreated(function () {
// will re-run when the "limit" reactive variables changes
instance.autorun(function () {
// get the limit
var limit = instance.limit.get();
console.log("Asking for "+limit+" posts…")
// subscribe to the posts publication
var subscription = instance.subscribe('posts', limit);
// if subscription is ready, set limit to newLimit
if (subscription.ready()) {
console.log("> Received "+limit+" posts. \n\n")
instance.loaded.set(limit);
} else {
console.log("> Subscription is not ready yet. \n\n");
}
});
});
I suppose you could if you only want global, automatically-activated subscriptions. For some small apps that makes sense. As your code grows in complexity you may want more fine-grained control over your subscriptions. Generally speaking, you have three patters for placing subscriptions in your app (in order of granularity and control):
Globally (as suggested in your question)
In the router - assuming you use iron router
In the template. Also see this post for additional template subscription examples.
While the community has recently fallen in love with template subscriptions, I'm not prepared to make a general recommendation that they are always they way to go. As you move up the subscription hierarchy, you lose some control but also gain reusability.
Let's take a simple example - imagine you have a social app and you have a list of friends. Let's say the majority of routes and templates assume the existence of your fiends' user data. If each template or route made the same subscription for this list, you'd end up with a lot of duplication and, potentially, a lot of unnecessary starting and stopping (this translates to server load and network bandwidth). On the other hand, had you made your friends a global subscription, those performance pitfalls could have been avoided.
Try to use template based subscriptions if possible. In that case, if you have /client/templates/home.html, you would put subscriptions related to that template in /client/templates/home.js for example.
Template.home.onCreated(function() {
this.subscribe('somePublication');
});
In my experience, the better way to manage the subscriptions is using the template subscription pattern pattern
Snippet taken from the reference:
Template.posts.onCreated(function () {
// 1. Initialization
var instance = this;
// initialize the reactive variables
instance.loaded = new ReactiveVar(0);
instance.limit = new ReactiveVar(5);
// 2. Autorun
// will re-run when the "limit" reactive variables changes
instance.autorun(function () {
// get the limit
var limit = instance.limit.get();
console.log("Asking for "+limit+" posts…")
// subscribe to the posts publication
var subscription = instance.subscribe('posts', limit);
// if subscription is ready, set limit to newLimit
if (subscription.ready()) {
console.log("> Received "+limit+" posts. \n\n")
instance.loaded.set(limit);
} else {
console.log("> Subscription is not ready yet. \n\n");
}
});
// 3. Cursor
instance.posts = function() {
return Posts.find({}, {limit: instance.loaded.get()});
}
});
I've actually been toying with Meteor for a little bit now, but I realized that I still lack some (or a lot!) comprehension on the topic.
For example, here is a tutorial that uses node.js/express/socket.io to make a simple real-time chat: http://net.tutsplus.com/tutorials/javascript-ajax/real-time-chat-with-nodejs-socket-io-and-expressjs/
In that above example, through socket.io, the webserver receives some data and passes it onto all of the connected clients -- all without any database accesses.
With Meteor, in all the examples that I've seen, clients are updated by writing to the mongodb, which then updates all the clients. But what if I don't need to write data to the database? It seems like an expensive step to pass data to all clients.
I am sure I am missing something here. What would be the Meteor way of updating all the clients (say, like with a simple chat app), but without needing the expense of writing to a database first?
Thank you!
At the moment there isn't an official way to send data to clients without writing it to a collection. Its a little tricker in meteor because the step to send data to multiple clients when there isn't a place to write to comes from when multiple meteor's are used together. I.e items sent from one meteor won't come to clients subscribed on the other.
There is a temporary solution using Meteor Streams (http://meteorhacks.com/introducing-meteor-streams.html) that can let you do what you want without writing to the database in the meanwhile.
There is also a pretty extensive discussion about this on meteor-talk (https://groups.google.com/forum/#!topic/meteor-talk/Ze9U9lEozzE) if you want to understand some of the technical details. This will actually become possible when the linker branch is merged into master, for a single server
Here's a bit of way to have a 'virtual collection, its not perfect but it can do until Meteor has a more polished way of having it done.
Meteor.publish("virtual_collection", function() {
this.added("virtual_coll", "some_id_of_doc", {key: "value"});
//When done
this.ready()
});
Then subscribe to this on the client:
var Virt_Collection = new Meteor.Collection("virtual_coll");
Meteor.subscribe("virtual_collection");
Then you could run this when the subscription is complete:
Virt_Collection.findOne();
=> { _id: "some_id_of_doc", key: "value"}
This is a bit messy but you could also hook into it to update or remove collections. At least this way though you won't be using any plugins or packages.
See : https://www.eventedmind.com/posts/meteor-how-to-publish-to-a-client-only-collection for more details and a video example.
The publish function on the server sends data to clients. It has some convenient shortcuts to publish query results from the database but you do not have to use these. The publish function has this.added(), this.removed(), and this.changed() that allow you to publish anything you choose. The client then subscribes and receives the published data.
For example:
if ( Meteor.isClient ){
var someMessages = new Meteor.Collection( "messages" ); //messages is name of collection on client side
Meteor.subscribe ( "messagesSub" ); //messagesSub tells the server which publish function to request data from
Deps.autorun( function(){
var message = someMessages.findOne({});
if ( message ) console.log( message.m ); // prints This is not from a database
});
}
if (Meteor.isServer ) {
Meteor.publish( "messagesSub", function(){
var self = this;
self.added ( "messages", "madeUpId1", { m: "This is not from a database"} ); //messages is the collection that will be published to
self.ready();
});
}
There is an example in meteor docs explained here and another example here. I also have an example that shares data between clients without ever using a database just to teach myself how the publish and subscribe works. Nothing used but basic meteor.
It's possible to use Meteor's livedata package (their DDP implementation) without the need of a database on the server. This was demoed by Avital Oliver and below I'll point out the pertinent part.
The magic happens here:
if (Meteor.isServer) {
TransientNotes = new Meteor.Collection("transientNotes", {connection: null});
Meteor.publish("transientNotes", function () {
return TransientNotes.find();
});
}
if (Meteor.isClient) {
TransientNotes = new Meteor.Collection("transientNotes");
Meteor.subscribe("transientNotes");
}
Setting connection: null specifies no connection (see Meteor docs).
Akshat suggested using streams. I'm unable to reply to his comment due to lack of reputation, so I will put this here. The package he links to is no longer actively maintained (see author's tweet). I recommend using the yuukan:streamy (look it up on Atmosphere) package instead or use the underlying SockJS lib used in Meteor itself—you can learn how to do this by going through the Meteor code and look how Meteor.server.Stream_server, and Meteor.connection._stream are used, which is what the Streamy package does.
I tested an implementation of the Streamy chat example and found performance to be negligibly different but this was only on rudimentary tests. Using the first approach you get the benefits of the minimongo implementation (e.g. finding) and Meteor reactivity. Reactivity is possible with Streamy, though is does through things like using ReactiveVar's.
There is a way! At least theoretically The protocol used by Meteor to sync between client and server is called DDP. The spec is here
And although there some examples here and here of people implementing their own DDP clients, I'm afraid haven't seen examples of implementations of DDP servers. But I think the protocol is straightforward and would guess it wouldn't be so hard to implement.
Is there a way to subscribe to the Meteor Session object so that a reactive template view automatically renders when data is .set on the Session object? Specifically the key/name and value data?
I have a similar question related to rendering Meteor Session object data when iterated over. This question is specifically different on purpose. I want to get an answer out on an alternate way and possibly better way to do the same thing.
I do not want to have to call Session.get('name'); This use case is because I don't know the names in the Session object.
So, I would like to be able to have something in handlebars that allows me to
Psuedo code...
{{#each Session}}
{{this.key}} {{this.value}}
{{/each}}
Unsure about subscribing to the session, but for the second part of your question, you can use this:
Template.hello.session = function () {
map = []
for (prop in Session.keys) {
map.push({key: prop, value: Session.get(prop)})
}
return map
}
then in your template:
{{#each session}}
{{key}} {{value}}
{{/each}}
Not sure if there's a more elegant way but it works.
I don't think so.
Have a look at https://github.com/meteor/meteor/blob/master/packages/session/session.js. It's actually reasonably simple. The invalidation happens in lines 45-47. You'll see calling Session.set invalidates anyone listening to that key specifically (via Session.get) or to the new or old value (via Session.equals). Nothing in there about invalidating the session as whole.
On the other hand, considering how simple it is, it wouldn't be super hard to write your own data structure that does what you want. I'm not sure what your use case is, but it might make a lot of sense to separate it from the session.
Yes you can subscribe to Session values.
Take a look a the docs for autosubscribe:
http://docs.meteor.com/#meteor_autosubscribe
// Subscribe to the chat messages in the current room. Automatically
// update the subscription whenever the current room changes.
Meteor.autosubscribe(function () {
Meteor.subscribe("chat", {room: Session.get("current-room");});
});
This code block shows one way to use this. Basically any time the value of "current-room" is changed Meteor will update the views.
EDIT
I misunderstood the initial question and decided I need to redeem myself somewhat. I just did some tests and as far as I can tell you can currently only subscribe to collection.find() and session.get() calls. So you can't subscribe to the whole session object or even to the keys object.
However, you can set a Session value to an object this may not be the most elegant solution but this worked for me on keeping track of the keys object with some hackery to keep from getting a circular object error.
var mySession = {
set: function(key, val){
var keys = Session.keys,
map = {};
Session.set(key, val);
for (var prop in keys) {
if(!(prop === "keys")){
map[prop] = keys[prop];
}
}
Session.set('keys', map);
}
};
This gives you something that looks a lot like original functionality and can help you keep track and update templates as you add or change Session values.
Here's my template helper (borrowed from previous answer):
Template.hello.keys = function() {
map = [];
keys = Session.get('keys');
for (var prop in keys) {
map.push({key:prop, value:keys[prop]});
}
return map
};
And here's the actual template:
<template name="hello">
<div class="hello">
{{#each keys}}
{{key}} {{value}} <br />
{{/each}}
</div>
</template>
This way you can just call mySession.set("thing", "another thing") and it will update on screen. I am new to Javascript so someone please let me know if I'm missing something obvious here, or let me know if there is a more elegant way of doing this.
While accessing the session object in this manner is doable .. You're not drinking the cool-aid.
In other words, Meteor excels in the respect of having publish/subscribe. Its not clear (to me) how much data you've got to put into the Session object before a browser crashes; I would rather not find out.
You would merely put all your session dependent code in a Deps.autorun() function to plug into subscriptions as mentioned in an earlier answer. Any time a session changes it'll modify the subscription; you can attach a ready callback, or use subscription.ready() checks to initiate specific actions, but ideally you'd structure your templates in a way that you could use rendered/destroyed functions, taking care to use {{isolate}}/{{constant}} when possible.
What you're getting at is kind of a difficult way to do something simple; and may not adhere to changes in meteor in the future; we can always be assured publish/subscribe will function as expected... Given Session is such a simple object.. whats to say someone designs something better shortly.. and it gets merged into meteor; and you're left with some weird workflow based on custom objects that may not break the Session; but may impact other parts of your interface.
I am developing a metro application and I want to create some async operations whose my own classes would implement.
I have found just examples of async using WinRT operations (e.g. CreateFileAsync). I do not find any intance where someone is creating a async method and consuming it.
Now you can do it. Look at this:
http://blogs.msdn.com/b/nativeconcurrency/archive/2011/10/27/try-it-now-use-ppl-to-produce-windows-8-asynchronous-operations.aspx
http://code.msdn.microsoft.com/Windows-8-Asynchronous-08009a0d
WinRT Async Production using C++
Use create_async in C++:
IAsyncOperationWithProgress<IBuffer^, unsigned int>^ RandomAccessStream::ReadAsync(IBuffer^ buffer, unsigned int count, InputStreamOptions options)
{
if (buffer == nullptr)
throw ref new InvalidArgumentException;
auto taskProvider = [=](progress_reporter<unsigned int> progress, cancellation_token token)
{
return ReadBytesAsync(buffer, count, token, progress, options);
};
return create_async(taskProvider);
}
Use AsyncInfo.Run in .NET:
public IAsyncOperation<IInfo> Async()
{
return AsyncInfo.Run(_ =>
Task.Run<AType>(async () =>
{
return await DoAsync();
})
);
}
I posted the same question in Microsoft forums and they gave me two replies. The first was:
Hi Claudio,
In the Developer Preview there isn't an easy way to create your own
async operations. We are aware of this shortcoming and are trying to
solve it for the next pubic release. In the meanwhile, you could
design your API as async and we will provide guidance on how to
convert sync to async.
Thanks
Raman Sharma, Visual C++
When I asked for the hard way to do this, another guy, someone responsible for PPL said me:
We’re planning to do a refresh of the sample pack we released a few
weeks ago and add a few samples on creation of async operations. I
expect that it will happen in a couple of weeks or so. If you keep an
eye on our blog at http://blogs.msdn.com/b/nativeconcurrency, you’ll
be the first to know.
As to how hard it is... The general-purpose solution that we’re
contemplating is about 1000 lines of C++ code making copious use of
template metaprogramming. Most of it will be in the header file so you
can explore it yourself. While a less general solution can be less
complex, you will still need to implement a base class, do the state
management, error handling etc. At this moment I can’t go into more
detail, but I will say that you will love how easy it is to author
async operations with PPL – so hang in there!
Artur Laksberg PPL team
Then, there is no solution at that time. Thank you all.
Yes, see Ben Kuhn's //BUILD/ talk: http://channel9.msdn.com/events/BUILD/BUILD2011/PLAT-203T He shows how to build an asynchronous API.
At the current time, there is no good solution for high level (C++/WX) classes. However if you use the low level C++ interfaces, you can use the WRL::AsyncBase class to help build your async interfaces.
Here is documentation about the AsyncBase class.
It is confusing, but there is a difference between WinRT C++ code and WRL. You can use WRL to code to the ABI layer directly. WRL does not use exceptions, but loves templates. The recommend coding style for WinRT is not the same as WRL.
I am not sure if everyone can do this, but using WRL you in general need to implement a class that inherits:
class CreateAysncOp: public RuntimeClass<IAsyncOperation<result_runtime_class*>,AsyncBase<IAsyncCompletedHandler<result_runtime_class*>>
{
...
Then you can use
hr = MakeAndInitialize<CreateAsyncOp, IAsyncOperation<type_foo*>>(...);
C++ WinRT is now the best way to implement WinRT async methods. This uses co_await and co_return, new C++ language features (in the process of standardization). Read the docs on this page.