React.js Dataflow Paradigm - how are data.props, state, and JSX beneficial? - javascript

I'm using React and created a small page that has 4 components (React classes, what is the preferred term? I'll call them components in this post):
Component Breakdown
a parent "App" component that includes and manages the other components
a "Form" component that lets the user interact with the page
a "String View" component that displays the input from the form as text
a "Visual View" (I know, bad name...) component that interprets the string view and performs actions to adjust the visual.
Dataflow
The communication of these components using states and props is as follows:
The Form has onChange handlers that pass the new state to the App
The App funnels the state data to the String View
The String View updates and passes the updated state to the App
The App funnels the new state data to the Visual View
Finally, the Visual View now updates based on the new state.
Sample Code
var App = React.createClass({
handleFormChange: function(formData) {
this.setState({formData:formData});
},
handleStringChange: function(stringData) {
this.setState({stringData:stringData});
},
render: function() {
return (
<div className="app">
<FormView onFormChange={this.handleFormChange}/>
<StringView formData={this.state.formData} onStringChange={this.handleStringChange}/>
<VisualView stringData={this.state.stringData}/>
</div>
);
}
});
var FormView = React.createClass({
handleFormChange: function(e) {
this.props.onFormChange(e.target.value);
}
render: function() {
return(
<div className="formView">
<select onChange={this.handleFormChange}>
<option value="1">Option 1</option>
<option value="2">Option 2</option>
</select>
</div>
);
}
});
var StringView = React.createClass({
componentDidUpdate: function() {
this.props.onStringChange({newString:'newStringState'});
},
render: function() {
this.props.formData;
// process formData and update state
return (
<div className="stringView">
{this.props.formData}
</div>
);
}
});
var VisualView = React.createClass({
render: function() {
var selection = this.props.stringData,
output = '';
if (selection === 1) {
output = 'Hooray, 1!';
} else {
output = 'Yes! 2!';
}
return (
<div className="stringView">
{output}
</div>
);
}
});
Questions
Is this the correct dataflow paradigm that React is trying to enforce (components only talk to parents, not siblings)?
Compared to how I would have written this in just regular JavaScript, this seems terribly constrained. Am I missing the big picture? Is this dataflow paradigm designed to prevent future problems (if so, which ones? Any that can't be solved with disciplined regular JavaScript?), or is there some other purpose that I'm missing?
I'm getting a lot of repeated function names (handleFormChange for example, it's used in App and Form View), is there a good way to make these distinguishable? Or, are repeated function names across components desirable?
When the components actually build, the JSX stuff gets transpiled down into real JavaScript. Is there an advantage to using JSX? Would writing components in the already transpiled JavaScript have an advantage?

To start, I think it is ok to call "components", and I've seen lot of people call that way. I will answer your questions below, in an order that I think is better to make my answers make sense.
When the components actually build, the JSX stuff gets transpiled down into real JavaScript. Is there an advantage to using JSX? Would writing components in the already transpiled JavaScript have an advantage?
JSX kinda mixes JavaScript and HTML, so, it makes your code "friendly". You will create your components, and just "call" them as HTML tags. Below you can see the difference between writing JSX and pure JavaScript.
return <div className="my-component"><p>Awesome</p></div>;
return ReactDOM.div({
className: 'my-component'
}, ReactDOM.p({}, "Awesome"));
I don't know you, but I would get tired to write this amount of code just to render a div with a paragraph.
You can check more benefits of using it here:
https://hchen1202.gitbooks.io/learning-react-js/content/benefits_of_jsx.html
I'm getting a lot of repeat function names (handleFormChange for example, it's used in App and Form View), is there a good way to make these distinguishable? Or, are repeated function names across components desirable?
It is not bad, also, your app is a "demo" one, if it would be a "real" one, it would have some better names for the components (i.e. <FormView> would be <ContactForm>) and maybe your method names would be different. But it is not bad at all. For example, inside <ContactForm> you may call the submit handler as onSubmit, but outside (the prop that you pass), you may call onContactFormSubmit, or, in a more semantic way, onContactFormFilled.
If your application starts to grow and you have lots of things repeated in the same component (that is the case of your <App>), you may try to split your components, therefore, each of your component will "know" about a "domain", and it would not appear to have lots of repeated stuff.
Is this the correct dataflow paradigm that React is trying to enforce (components only talk to parents, not siblings)?
First of all, React doesn't "enforce" anything, as some people say, React is the "v" in MVC, so, you have your "presentation" layer described as components, and the data may flow in the way you want.
But you got a point when you say "components only talk to parents, not siblings", because that is the way you can "communicate" between your components when you have multiple components. Since a component can't see its sibling, you need someone to orchestrate this communication, and, in this case, this is the parent's job.
There are other ways to make components "talk" to each other (i.e. using refs), but having a parent to orchestrate is, IMO, the most reliable (and better testable) one.
Compared to how I would have written this in just regular JavaScript, this seems terribly constrained. Am I missing the big picture? Is this dataflow paradigm designed to prevent future problems (if so, which ones? Any that can't be solved with disciplined regular JavaScript?), or is there some other purpose that I'm missing?
I decided to answer that as the last one, to sum up some things.
IMO, React is just great, you start to have your "logic" in the right place (a component), and you can just compose things in order to make your page work well (and by well I mean it is orchestrated correctly).
React also makes it easier to "think" about how you will build your interfaces. This Pete Hunt's blog post is amazing, and you should check it out:
https://facebook.github.io/react/docs/thinking-in-react.html
If you would be writing your code with plain JavaScript, you would have to handle DOM in some way (i.e. using a template engine) and your code would end up mixing DOM manipulation with your application logic. React just abstracts that for you. You can only care about presenting stuff. Another advantage is that, when everything is a component, you can reuse those components, it doesn't matter where they are located. If you pass the props correctly, your component will work as expected.
I know it seems exhaustive to write those components, but as you start to write more components you start to see lots of benefits. One of them is to nevermore wonder about how to present your data (no more concatenating HTML strings or calling template functions). Another one is that it is easy to "split" your interfaces, what makes your code easier to maintain (and that is not straightforward when using plain JavaScript).
To be honest, this application you wrote is really simple, and you may not see lots of advantages of using React for building it. I think you should try to create a more "complex" one, and compare it with plain JavaScript. By "complex", I mean "user interface" complex. For example, create a form that allows user to submit multiple "people". And "people" should have "name" and multiple "pet" (which also have a name). You will see how hard is it to handle "add" and "remove" operations in this case, and how easy React handle that kind of thing.
I think that is it, I hope you and React "click". It changed my mind about how to create complex user interfaces.

Related

Backbone views which don't know about their container, models to be fetched via AJAX, no UI/UX trade-offs and maintainable code

Since I'm not totally sure on which level my issue actually is to be solved best, I'd like to summarise the path I went and the things I tried first:
It's more or less about $el (I think).
As most basic backbone examples state, I started with having the $el defined within its view, like
Invoice.InvoiceView = Backbone.View.extend({
el: $('#container'),
template: ..,
..
});
It didn't feel right, that the view is supposed to know about its parent (=container). The paragraph 'Decouple Views from other DOM elements' written on http://coenraets.org/blog/2012/01/backbone-js-lessons-learned-and-improved-sample-app/) perfectly puts it into words.
Following this article's advice, I switched to passing $el over to the view while calling the render()-method. Example:
$('#container').html( new WineListView({model: app.wineList}).render().el );
So far so good - but now render() gets called, while it maybe shouldn't (yet).
For example the View asynchronously fetches a model in its initialize()-routine. Adding a binding to reset or sync (e.g. like this.model.bind('sync', this.render, this)) makes sure, render() gets definitely called once the model is fetched, however above stated way, render() still might get called while the model isn't fetched yet.
Not nice, but working(TM), I solved that by checking for the model's existence of its primary key:
render: function() {
if(this.model.get('id')) {
...
}
However, what I didn't expect - and if it really isn't documented (at least I didn't find anything about it) I think it really should be - the fetch operation doesn't seem to be atomic. While the primary key ('id') might be already part of the model, the rest might not, yet. So there's no guarantee the model is fetched completely that way. But that whole checking seemed wrong anyway, so I did some research and got pointed to the deferred.done-callback which sounded exactly what I was looking for, so my code morphed into this:
render: render() {
var self = this;
this.model.deferred.done(function() {
self.model.get('..')
};
return this;
}
..
$('#container').html( new WineListView({model: app.wineList}).render().el);
It works! Nice, hu? Ehrm.. not really. It might be nice from the runtime-flow's point of view, but that code is quite cumbersome (to put it mildly..). But I'd even bite that bullet, if there wouldn't be that little, tiny detail, that this code sets (=replaces) the view instantly, but populates it later (due to the deferred).
Imagine you have two (full-page) views, a show and an edit one - and you'd like to instantly switch between the two (e.g. after hitting save in the edit-view it morphs into the show-view. But using above code it sets (=resets) the view immediately and then renders its content, once the deferred fires (as in, once fetching the model is completed).
This could be a short flickering or a long blank transition page. Either way, not cool.
So, I guess my question is: How to implement views, which don't know about their container, involve models which need to be fetched, views which should be rendered on demand (but only once the model is fetched completely), having no need to accept UI/UX trade-offs and - the cherry on the cake - having maintainable code in the end.
First of all, the first method you found is terrible (hard coding selector in view's constructor)
The second: new WineListView({model: app.wineList}).render().el is very common and ok. This requires you to return the reference to view from render method, and everyone seems to follow this, which is unnecessary.
The best method (imo) is to simply attach the views element to the container, like this
$('#container').html(new WineListView({model: app.wineList}).el);
The WineListView doesn't need to know about where it's going to be used, and whatever is initializing WineListView doesn't need to worry about when to render the WineListView view instance:
because the el is a live reference to an HTML Element, the view instance can modify it anytime it wants to, and the changes will reflect wherever it is attached in DOM/ when it gets attached in DOM.
For example,
WineListView = Backbone.View.extend({
initialize: function(){
this.render(); // maybe call it here
this.model.fetch({
success: _.bind(this,function(){
this.render(); // or maybe here
})
});
}
});
Regarding flickering: this hardly has to do anything with rendering or backbone, it's just that you're replacing one element with another and there will be an emptiness for a tiny bit of time even if your new view renders instantly. You should handle this using general techniques like transitions, loaders etc, or avoid having to switch elements (For example convert labels into inputs in the same view, without switching view)
First off, the linked example is outdated. It's using version 0.9.2,
whereas the current version (2016-04-19) is 1.3.3. I recommend
you have look at the change log and note the differences, there are many.
Using the el property is fine. Like everything though, there's a time and place.
It didn't feel right, that the view is supposed to know about its parent (=container). The paragraph 'Decouple Views from other DOM elements' written on http://coenraets.org/blog/2012/01/backbone-js-lessons-learned-and-improved-sample-app/) perfectly puts it into words.
I wouldn't define an el property on every view, but sometimes it makes sense, such as your example. Which is why, I'm assuming, Backbone allows the use of the el property. If you know container is already in the DOM, why not use it?
You have a few options:
The approach outlined in my original answer, a work-around.
fetch the model, and in the success callback, insert the view element into the DOM:
model.fetch({
success:function() {
$('#container').html(new View({model:model}).render().el);
}
});
Another work-around.
Define an el property on the view and fetch the model in the view initialize function. The new content will be rendered in the container element (also the view), when the content/model data is ready, by ready, I mean when the model has finished fetching from the server.
In short,
If you don't want to define an el property, go with number 1.
If you don't want to let the view fetch the model, go with number 2.
If you want to use the el property, go with number 3.
So, I guess my question is: How to implement views, which don't know about their container
In your example, I would use the el property, it's simple a solution with the least amount of code. Not using the el property here, turns into hacky work-arounds that involve more code (complexity) without adding any value (power).
Here's what the code looks like using el:
var Model = Backbone.Model.extend({url:'/model_url'});
var model = new Model();
// set-up a view
var View = Backbone.View.extend({
el:'#container',
template:'model_template',
initialize:function() {
this.model.fetch();
this.listenTo(this.model,'sync',this.render);
},
render:function() {
this.$el.html(this.template(this.model.toJSON()));
return this;
}
});
var view = new View({model:model});
Check out the documentation for el.
Here is an updated working example.
If there is an obvious flicker because, your model takes a noticeable amount of time
to be fetched from the server...maybe you should think about displaying a loading bar/variation thereof
while fetching the model. Otherwise instead of seeing the flicker, it will appear the
application is slow, delayed, or hanging..but in reality - it's waiting to render the next view,
waiting for the model to finish fetching from the server. Sitting on old content, just waiting for
the model to load new data to show new content.

How can I enforce privacy on State variables in a Flux Store?

I have a small, home-brewed implementation of the Flux pattern that I'm working with, just to get a better understanding of the pattern. Its working quite well, and I'm learning a ton! But I've run into an issue I can't wrap my head around at the moment. Apologies in advance if this has an obvious solution.
Imagine my simple Store called ExampleStore, and my simple Component ExampleComponent. In it there are:
_exampleState
getExampleState()
setExampleState()
in ExampleComponent, to stay updated:
_onChange: function() {
setState({exampleState: ExampleStore.getExampleState()})
}
in ExampleStore, after a dispatched action I use the setter:
setExampleState(newStateFromDispatchedAction);
This works perfectly. The data is flowing as it should. But I have a question, because it seems easy to break the pattern because there is no privacy enforced on my _exampleState within my Store. Since I have a getter and private setter method for _exampleState, it seems natural to me that somehow I want to enforce more privacy on the variable. Is there a nifty way to do this, that I am overlooking?
As it is now, if, for example, inside ExampleComponent I do (which I wouldn't, but I could):
this.state.exampleState = {field:'example'}
//doing this
this.state.exampleState.field = 'example2';
//changes the store _exampleState to {field:'example2'}
I have changed the value of _exampleState within ExampleStore directly, without making use of the setter. This seems dangerous (and makes me question why I'd have a private setter/public getter to begin with). This question comes after dealing with a pesky bug where a library I was using modified the state variable directly, and thereby within the Store.
Is there some good way I'm overlooking to enforce privacy on the state variables in my Store, so that they may not be changed directly through their references in ExampleComponent? Sorry if this is a dumb question and I'm overlooking something simple, thanks for the help!
Be aware that one of the basic principles of the Flux philosophy is that stores should have no (public) setters. That means you should not be able to modify the store's state if not inside the store itself.
One way of enforcing the privacy could be by keeping state variables as private, only letting the store managing them.
EDIT: to "enforce" privacy, you could also return a deep copy of your state, as it is shown in the code.
The following code, based on the official flux GitHub repository's flux-todomvc example, highlights the idea:
var AppDispatcher = require('../dispatcher/AppDispatcher');
var AppConstants = require('../constants/AppConstants');
var EventEmitter = require('events').EventEmitter;
var assign = require('object-assign');
// This is a private state variable that can only be accessed in this file
var _exampleState = {/*...*/};
var ExampleStore = assign({}, EventEmitter.prototype, {
EXAMPLE_STATE_CHANGED: 'EXAMPLE_STATE_CHANGED',
// return a deep copy of your state so there is no way
// to modify the store's state by reference
getExampleState: function() {
return deepCopy(_exampleState);
}
/*...*/
};
// this is a private method (setter)
var _setExampleState = function(newExampleState) {
_exampleState = newExampleState;
};
ExampleStore.dispatchToken = AppDispatcher.register(function(action) {
switch(action.actionType) {
case AppConstants.CHANGE_EXAMPLE_STATE:
_setExampleState(action.newExampleState);
ExampleStore.emit(ExampleStore.EXAMPLE_STATE_CHANGED);
break;
}
});
// the implementation of deepCopy is a developer's choice
// this version of it is very inefficient
var deepCopy = function(obj) {
return JSON.parse(JSON.stringify(obj));
}
module.exports = ExampleStore;
Facebook official examples are a good way to understand how to implement the core Flux concepts.
EDIT: this is a way of "enforcing" privacy of a state variable, but it is discouraged due to the clear loss of efficiency. I guess that the main idea here is that, even though you are able to do so in some situations, changing the store's state through reference is just against Flux. It is important to notice that this enforcement is not a reality in many big libraries. In React, for instance, it is possible to modify the state of a component directly, even though that is completely not recommended.
you can wrap your store in a closure, and provide getters and setters, to prevent accidental modification of your state.
https://facebook.github.io/immutable-js (or Mori or seamless-immutable) provides the means to prevent modifications to nested data, while avoiding the need to make defensive deep clones in your getExampleState method. However, it has a huge impact on your coding style and code base. It possibly works best with a functional coding style, as is encouraged by some flux implementations, like https://github.com/rackt/redux.
Another option is to make it clearer that you don't want the state to be modified by ensuring that non-library code only sees the store state in React 'props', rather than React 'state' - not modifying props should be second nature to a React developer anyway (other bugs will occur if they modify it). This can be done using a generic flux wrapper component, such as Facebook's 'Container' - https://facebook.github.io/flux/docs/flux-utils.html

Combination of Angular & React to streamline

I'm currently making the change from Angular routing & client-side rendering to React & Flux for isomorphic builds. I've just started learning React so bear with me.
Here's my problem. To render a simple list, it would look like this.
HTML, component & render in React:
<!--html-->
<div id="mount-point"></div>
<script type="text/jsx">
//component
var List = React.createClass({
getInitialState: function(){
return {
items: [
"Apples",
"Broccoli",
"Chicken",
"Duck",
"Eggs",
"Fish",
"Granola",
"Hash Browns"
]
}
},
render: function(){
return (
<ul>
{
this.state.items.map(function(item) {
return <li key={item}>{item}</li>
})
}
</ul>
)
}
});
//render
React.render(<List/>, document.getElementById('mount-point'));
</script>
Or in Angular, with a controller and HTML:
<script>
//controller
app.controller("MyController", ["$scope", function($scope){
$scope.items = [
"Apples",
"Broccoli",
"Chicken",
"Duck",
"Eggs",
"Fish",
"Granola",
"Hash Browns"
]
}]);
</script>
<!--html-->
<ul>
<li ng-repeat="item in items">{{item}}</li>
</ul>
Now to me, the Angular code looks a lot shorter and more readable. The HTML where data is injected is not infiltrated by javascript code. I'm not trying to start a React v Angular debate. Instead, I'm wondering if there is a way to combine the best properties of both? i.e. have the stateful component concept from React but instead of using raw javascript in the JSX, using things like Angular's ng-repeat. If not, is there another way to approach writing the JSX in my example?
IMHO, the React code is better and more readable because it is just javascript. It doesn't require (hardly) any extra knowledge to understand what's going on. You read the angular one, and if you're not familiar at all with angular, you're immediately wondering: what's $scope? what's app? what's controller do? why do i pass it an array and why is the second argument a function? what calls this function? what's an ng-repeat? this list goes on ...
Now, on to your question: No.
The JSX you've written is perfect (well, sort of, I'll add my modifications below). Why is it perfect? It's perfect because nearly any programmer on the planet can figure out what it does: it maps over a list of items.
Now, if I were to rewrite it, I'd do something like this:
var List = React.createClass({
...
renderItem: function(item, key) {
return <li key={key}>{item}</li>;
},
render: function() {
return <ul>{this.state.items.map(this.renderItem)}</ul>;
}
}
Creating a separate renderItem function to render the item will make this a lot more future-proof (and readable IMO). Also, you shouldn't put your key as the item itself, because (in this example) that would prevent two items from having the same value (ie, two "Apple"s)
It seems like maybe what you're really asking is, "directives in angular are cool! why doesn't react have directives? and can/should I add directives to React?"
If I were to address that, I'd say... directives do seem cool in angular. Although, there's clearly some big problems with them, even the angular team abandoned them (custom ones anyway) in angular 2. There is some react library on github floating around right now that adds ng-like directives to JSX, but I highly advise against it. It's really just a bad idea. I'm going to repeat this for double extra super clarity: It's a bad idea. What's wrong with writing plain old javascript and rendering it with JSX handlebars? Do you really need an ng-repeat because writing list.map is too hard? The added complexity and learning curve, however slight, far outweighs the benefits. render() is a beautiful pure function, let's leave it that way.
You can actually interoperate Angular and React using https://github.com/bcherny/ngimport. We've used it successfully on a 10k file hybrid Angular+React project - let me know if I can answer any questions!

True custom attributes (e.g. Microdata) in React

The site I am developing makes use of Microdata (using schema.org). As we are shifting development over to use React to render our views I have hit a blocker where React will only render attributes in the HTML spec however Microdata specifies custom attributes such as itemscope.
As I'm relatively new to React and haven't had chance to fully understand the core just yet, my question is what would be the best way to extend the functionality of react.js to allow for defined custom attributes, e.g., Microdata?
Is there a way of extending the attributes/props parser or is it a job for a mixin which checks all passed props and modifies the DOM element directly?
(Hopefully we'll be able to put together a drop in extension for everyone to provide support for this when a solution is clear.)
You can also use "is" attribute. It will disable the attribute white-list of React and allow every attribute. But you have to write class instead of className and for instead of htmlFor if you use is.
<div is my-custom-attribute="here" class="instead-of-className"></div>
Update React 16 custom attributes are now possible
In react 16 custom attributes are now possible
React 16 custom attributes
It looks like these non-standard properties have been added to React
itemProp: MUST_USE_ATTRIBUTE, // Microdata: http://schema.org/docs/gs.html
itemScope: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE, // Microdata: http://schema.org/docs/gs.html
itemType: MUST_USE_ATTRIBUTE, // Microdata: http://schema.org/docs/gs.html
Note that properties have capital letter in the middle:
<div itemProp="whatever..." itemScope itemType="http://schema.org/Offer">
will generate proper lowercase attributes as result.
You should be able to do it with componentDidMount:
...
componentDidMount: function() {
if (this.props.itemtype) {
this.getDOMNode().setAttribute('itemscope', true)
this.getDOMNode().setAttribute('itemtype', this.props.itemtype)
}
if (this.props.itemprop) {
this.getDOMNode().setAttribute('itemprop', this.props.itemprop)
}
}
...
The whole check for Microdata attributes can be wrapped into a mixin for convenient. The problem with this approach is that it won't work for built-in React component (components created by React.DOM). Update: Looking closer at React.DOM, I come up with this http://plnkr.co/edit/UjXSveVHdj8T3xnyhmKb?p=preview. Basically we wrap the built-in components in a custom component with our mixin. Since your components are built upon React 's built-in DOM components, this would work without you having to include the mixin in the components.
The real solution would be injecting a custom config instead of React's DefaultDOMPropertyConfig, however I can't find a way to do so in a drop-in manner (DOMProperty is hidden by the module system).
For those who's still looking for answers:
https://facebook.github.io/react/docs/tags-and-attributes.html
Example:
<div itemScope itemType="http://schema.org/Article"></div>
So far, the best method I've found is based off of some Amp interop code linked from a comment on react's bug tracker thread on the subject. I modified it slightly to work with a newer version of React (15.5.4) and TypeScript.
For regular ES6, you can just remove the type annotation for attributeName. Using require was needed in TS since DOMProperty isn't exposed in react's index.d.ts, but again import could be used in regular ES6.
// tslint:disable-next-line:no-var-requires
const DOMProperty = require("react-dom/lib/DOMProperty");
if (typeof DOMProperty.properties.zz === "undefined") {
DOMProperty.injection.injectDOMPropertyConfig({
Properties: { zz: DOMProperty.MUST_USE_ATTRIBUTE },
isCustomAttribute: (attributeName: string) => attributeName.startsWith("zz-")
});
}
Now you can use any attribute starting with zz-
<div zz-context="foo" />
Normally it'd be a bad idea to use internal parts of react like this, but I think it is better than any of the other methods. It works the same way as existing open-ended attributes like data- and the JSX is even type safe in TS. I believe the next major version of react is going to do away with the whitelist anyway, so hopefully changes won't be needed before we can remove this shim entirely.

Backbone showing/hiding rendered views best practices

New to using Backbone and have a very simple application. Basically there are Clients and ClientItems. I have a view to show all Clients and if you click on a Client you get taken to their ClientItems. Going to this ClientItems view should just hide the Clients view and going back to Clients should hide ClientItems. Now, in my render() function for each view, it is going through the collections and dynamically adding stuff to the page. When I go back and forth between the two (using the back button) I don't really need to fully render again as all the data is there in the page, just hidden. Where should this logic go? Right now I have it in the render() function but it feels sloppy, what is the preferred way of handling this?
We are using a global variable App with several common function used across application:
var App = {
initialize : function() {
App.views = {
clientView : new ClientsView(),
clientItemView : new ClientsItemsView()
}
},
showView: function(view){
if(App.views.current != undefined){
$(App.views.current.el).hide();
}
App.views.current = view;
$(App.views.current.el).show();
},
...
}
And then I use this App from other parts of application:
App.showView(App.views.clientView);
IntoTheVoid's solution is good – it's nice to have a single place to hide/show views. But how do you activate the logic?
In my experience, routers are the best place for this. When a route changes and the appropriate function is called, you should update the active, visible view(s).
What if you need multiple views to be visible at once? If you have a primary view that always changes when the route changes, and multiple subsidiary sticky views, you need not worry. But if it's more complex than that, think of creating a ComboView that neatly packages all the relevant views into one containing el node. That way the above logic still works, and your router functions are not littered with logic for managing what views are visible at the moment.

Categories