From the Flux's TodoMVC example, I saw the TodoApp component is asking the store to get the states.
Should the view create the action and let the dispatcher to call the store instead?
The views that are listening for the stores' "change" event are called controller-views, because they have this one controller-like aspect: whenever the stores change, they get data from the stores and pass it to their children through props.
The controller-views are the only views that should be calling the stores' getters. The getters should be the only public API that the stores expose. Stores have no setters.
It's very tempting to call the stores' getters within the render() method of some component deep in the tree, but this is an anti-pattern. It violates the unidirectional data flow, making it more difficult to understand the flow of data through the application, and it and makes your rendering more expensive.
In the TodoMVC Flux example, the TodoApp component is the only controller-view.
You should get the values from stores somehow:
Get value directly from store. E.g. postsStore.get('firstPost')
You'll not be notified on changes. So, don't use this method.
Get & Subscribe to store using lifecycle methods on component
componentWillMount: function(){
var _this = this;
myStore.subscribe(function(newValue){
_this.setState({
myValue: newValue
});
})
},
componentWillUnmount: function(){
// don't forget to unsubscribe from store here
}
Get & Subscribe to store using mixins. Usually Flux implementations gives you Mixin for it. So value from store setting to component state on changes of value in store.
example from Reflux
mixins: Reflux.connect(myStore, 'myValue'),
render: function(){
// here you have access to this.state.myValue
}
Subscribe to action. It can be useful for rendering errors, that you don't want to store. But you can use it for whatever you want.
Implementation same as previous, but instead store use action
Best way to sync with stores is to subscribe to store.
So answer to your question is:
Yes, it's ok, and No, you shouldn't call methods on stores in components.
It's ok to call methods on stores if it's pure methods (doesn't change data in store). So you can call only get methods.
But if you want (you should) to be notified on changes in store, you should subscribe to it. As manual subscribing can be added through mixins, it should use it (your own, or from flux-library). So SubscribingMixin(MyStore) calls some methods on store internally, but not you are right in component.
But if you think about reinvent Flux, notice, that there is no difference between subscribing to store and subscribing to action. So it's possible to implement it so all data will pass through actions.
View could get the states of Stores directly.
Action + Dispatcher is the flux way to change the states of the Store, not accessing existing Store data.
Related
During the bot builder v4 preview release I was able to get my state through the turnContext like so:
var state = await turnContext.GetConversationState<MyConversationState>();
state.CounterState.Count++; // state updated... no other steps
Now with the non preview release I have to setup accessors to get my state making the whole process very convoluted, like so:
var state = await _accessors.CounterState.GetAsync(turnContext, () => new CounterState());
state.TurnCount++;
await _accessors.CounterState.SetAsync(turnContext, state);
await _accessors.ConversationState.SaveChangesAsync(turnContext);
await turnContext.SendActivityAsync(responseMessage);
I understand how to use and implement the accessors I just get the use in them. Can someone explain why the second method above is better than the first? In the first method I had a state class that held all my data that I could manage within that class. Now from what I understand that class that I had before becomes an accessor?
you do not need to use accessors if you do not need/want to. They exist so that developers can expose only the properties they want to expose to specific components of their application.
An example could be if you were collecting personal data about a user in your app but had to pass off your state to be read/write to another component of your application that does not need the user's personal data. You can expose pieces of your state without exposing everything via accessors.
If you do not need this security/functionality you do not need to use accessors.
I have an app using React + Redux + Normalizr, I would like to know the best practices to reduce the number of renders when something changes on entities.
Right if I change just one entity inside the entities, it will re-render all the components and not only the components that need that specific entity
There are several things you can do to minimize the number of renders in your app, and make updates faster.
Let's look at them from your Redux store down to your React components.
In your Redux store, you can use immutable data structures (for example, Immutable.js). This will make all subsequent optimizations faster, as you'll be able to compare changes by only checking for previous/next state slice equality rather than recursively comparing all props.
In your containers, that is in your top-level components where you inject redux state as props, ask only for the state slices you need, and use the pure option (I assume you're using react-redux) to make sure your container will be re-rendered only if the state slices returned by your mapStateToProps functions have changed.
If you need to compute derived data, that is if you inject in your containers data computed from various state slices, use a memoized function to make sure the computation is not triggered again if the input doesn't change, and to keep object equality with the value the previous call returned. Reselect is a very good library to do that.
In your dumb components use the shouldComponentUpdate lifecycle to avoid a re-render when incoming props do not change. If you do not want to implement this manually, you can use React's PureRenderMixin to check all props for you, or, for example, the pure function from the Recompose library if you need more control. A good use case at this level is rendering a list of items. If your item component implements shouldComponentUpdate only the modified items will be re-rendered. But this shouldn't be a fix-all-problems habit : a good components separation is often preferable in that it makes flow props only to those components which will need them.
As far as Normalizr is concerned, there is nothing more specific to be done.
If in some case (it should be rare) you detect performance problems that are directly related to React's rendering cycles of components, then you should implement the shouldComponentUpdate() method in the involved components (details can be found in React's docs here).
Change-detection in shouldComponentUpdate() will be particularly easy because Redux forces you to implement immutable state:
shouldComponentUpdate(nextProps, nextState) {
return nextProps.dataObject !== this.props.dataObject;
// true when dataObject has become a new object,
// which happens if (and only if) its data has changed,
// thanks to immutability
}
I would like to "simulate" global variables in Angular. I would also like to be able to initialize those "global variables" in an App_Init()-type of handler. Such an initialization will require $http calls to populate those variables. I want all of the "global variables" to be completely loaded before Angular "calls up" controllers and views, because controllers would depend on the initialized data.
What are some best practices for that in Angular? Nested controllers? Services?
Example: An app that manages items in a restaurant's menu. Each item will be associated with a category (beverage, appetizer, dessert, etc.). I need to load all of those categories first before Angular "even touches" the controllers and views for the food items.
Are you using ng-view and the $routeProvider service for your app? Assuming you are or will consider, here is what you can do in order of steps:
Build a service that provides acces to the categories to its called. My idea is that this service would load the categories from the server when it's first called and then cache the data loaded, so the next time it's called a cache copy is served, instead, to save a request to the server. Let's call this service categories for now.
Use the resolve property of route object to ensure the dependency on the categories service is resolved before loading the view the user is requesting (and the corresponding controller). As a result, you can inject the categories service into the controller and be sure the service is always available because it has already been resolved.
If you have never worked with the resolve property in configuring routing before, Here is an example and the part of the official docs that talks about it. I recommend you go through them.
Also, in order to understand how resolve works, you need to be familiar with the concept of promise and deferred. If you are not, here is a good starting point on the topic. $q is AngularJS's implementation of promise/deferred.
I can't comment on if the above approach is the best practice, but I know it's a good practice to use service to provide access to some data/functions like if there were global variables.
You can create a service to load the configuration from server and put it in rootScope, in your controller you can call this service on your function and this function you call from ng-init in your view.
View
<mytag ng-init="myFunc()">
Controller
module.controller('MyCtrl', function($scope, myService){
$scope.myFunc = function(){
myService();
}
}
your service (initialize app)
module.service('myService', function($http, $rootScope){
//do something
$rootScope.config = configLoaded;
}
another tip
if you are in trouble with asynchronous calls you can try to use
var deferred = $q.defer();
//when your call come back
deferred.resolve(yourData);
//and in the last line of function
deferred.promise;
I want to create a subscriber that gets triggered when the user tries to access the resource (which is a custom content-type). So, the object is not being added, modified, nothing, is just being traversed. Something like a Zope View Event.
So, basically, suppose a custom content type has a custom workflow (two states: private and viewed). The initial state is private. This content type is only going to be created programatically, using _createObjectByType by anonymous users. Suppose an object called myobjet was added, programatically, to the root folder of my Plone site.
What I want is: when the user access
http://localhost:8080/Plone/myobject
...it automatically changes the state of the workflow of this object to viewed. The url http://localhost:8080/Plone/myobject is going to be a custom view, not the default base_edit.
Which event should I use? I tried IEndRequestEvent and IBeforeTraverseEvent from this list and none of them work: the handler is not being called for my custom object interface.
I've tried other events with my custom object interface (like IObjectEditedEvent), and, for this event, my handler is called when I edit an object that implements the interface. But using IEndRequestEvent and IBeforeTraverseEvent doesn't call the handler.
IEndRequestEvent and IBeforeTraverseEvent only work when I set the subscriber to all interfaces:
<subscriber
for="*
zope.app.publication.interfaces.IBeforeTraverseEvent"
handler=".subscriber.myhandler"
/>
And when I make myhandler print the object and the event in this situation, it shows:
<PloneSite at Plone>
<zope.app.publication.interfaces.BeforeTraverseEvent object at 0xd52618c>
If the solution is to write an event myself, is there an easy tutorial for this?
You might want to have a look at http://pypi.python.org/pypi/plone.validatehook.
Make sure you bind the event to the right interface. If you bind it to "Interface" (as described on the plone.validatehook pypi page) the event will get called for every single request. In order to restrict the event to contentish objects you can do the following:
from Products.CMFCore.interfaces import IContentish
#adapter(IContentish, IPostValidationEvent)
def RedirectMember(object, event):
...
(Edit: I removed my first answer because it didn't work)
Not sure what this subscriber is supposed to do, but if the object is not being modified, added or whatsoever than I must suspect it will just be viewed...so why not just use the __call__ method of the items view (or the __update__ method if you are using five.grok/dexterity)?
I am developing an application that involves a type hierarchy and started by defining the models for each type via inheritance. When it comes to writing the corresponding controllers I am not sure how to approach the whole thing in a clean way. Should I write only one controller for the base type that is able to handle derived models or should there be one controller for each subtype? How should the view-controller bindings be set up to work with the different controllers?
You might want to check out SproutCore's new experimental polymorphism support: http://groups.google.com/group/sproutcore-dev/browse_thread/thread/b63483ab66333d15
Here's some information on defining sub-classes and overriding properties and methods:
http://wiki.sproutcore.com/w/page/12412971/Runtime-Objects.
From my (limited) use of Sproutcore, I've only been able to bind 1 view to 1 controller.
As such, if you are planning to use a single view (e.g. ListView) to display your data, then I think you will only be able to bind that view to 1 controller. This means the 1 base type that is able to handle derived models seems to be the way to go.
Typically you populate the content of ArrayController instances with the results of App.store.find calls. SC.Store#find can take an SC.Query instance, which typically looks like:
MyApp.myController.set('content') = MyApp.store.find(SC.Query.local(MyApp.MyModel));
This should return all instances of MyApp.MyModel, including any instances of MyApp.MyModel's subclasses.
The first argument to SC.Query.local can either be an SC.Record subclass or a string referring to the subclass. So if you've got some intermediary SC.Record subclasses, you might want to try using them there.
Controllers should just be proxies for objects, when dealing with single instances of your model. In other words, ObjectController can proxy anything. Here is what I mean in code:
You have two objects, Person and Student.
App.Person = SC.Object.extend({
// person stuff here
})
App.Student = App.Person.extend({
// student stuff here, you have have all Person things because you are extending person.
})
You then want to define controllers:
App.personController = SC.ObjectController.create({
contentBinding: 'App.path.to.person'
})
App.studentController = SC.ObjectController.create({
contentBinding: 'App.path.to.student'
})
note that you would only bind the controller's content to something if the person/student is a result of a selection, or some other flow where bindings fire. In other words, if you set the person manually (say from a statechart, as the result of an interaction), you would still define the controller but would do
App.personController.set('content', person);
You set up the controller differently depending on whether the Person is a 'top level' object in your app, or some intermediate object that gets selected. Also, you might only need one controller, you would only have a studentController and a personController if you were acting on a person and a student at the same time. Both are just ObjectControllers, and those can proxy anything.
Finally, in your view you would bind the relevant view element to the controller:
...
nameView: SC.LabelView.design({
layout: {/* props */},
valueBinding: SC.Binding.oneWay('App.personController.name')
})
...
note that the oneway binding is if the name is not going to be changed on the view, if the view can change the name, then just do a normal binding. Also note the path here. I am not binding to
'App.personController.content.name'
Since the personController proxies the object, you bind to the
'namespace.controller.property-on-object-controller-proxies'
If you are putting a lot of business logic in your controller, you are doing it wrong. Controllers should just be for proxying objects (at least ObjectControllers should be). Business logic should be on the models themselves, and decision making logic should be in statecharts.