The syntax you’re talking about–taking from the React tutorial on the Meteor site–is:
AccountsUIWrapper = React.createClass({
componentDidMount() {
// Use Meteor Blaze to render login buttons
this.view = Blaze.render(Template.loginButtons,
React.findDOMNode(this.refs.container));
},
componentWillUnmount() {
// Clean up Blaze view
Blaze.remove(this.view);
},
render() {
// Just render a placeholder container that will be filled in
return <span ref="container" />;
}
});
So that means developers have to do this in their application client code, OR all the package authors have to make react versions of their code that already do this. Thats provided it works for anything but the most trivial use cases, and doesn’t require basically sideburns style transpiling of its own. Also, changes to packages won’t necessarily play nice with inter-opting packages that haven’t done it yet. That creates a mess of dependencies and incompatibilities–when many packages are dependent on each other, which they are.
As for the above example, the Template.loginButtons
example doesn’t take any parameters, i.e. isn’t passed any props
. Then you need to do Blaze.renderWithData(Template.loginButtons, this.props, React.findDOMNode(this.refs.container))
.
Then what if you are template uses “custom block helpers.” There’s no standards-based way to implement that. Blaze has no feature: Template.renderWithDataAndContentBlockAndElseBlock
. React has this.props.children
which is the equivalent of the contentBlock, but there’s no equivalent of elseBlock
. The most used packages make use of this dynamicism a lot to provide clean abstractions to application developers, the best example being @aldeed 's AutoForm.
Basically, doing anything beyond trivial stuff will likely take major work on either the package author’s part to provide a different version of their package, or application developers’ parts, if the package/component is in fact able to be composed in such a way.
In addition, it means you must ship both Blaze and React to the client. There’s probably many other pitfalls not discovered yet.
A robust solution that goes at the root will certainly save more time than all our collective work, and by several orders of magnitude. If it can be done, and it’s not that insane (which it isn’t), there’s no reason it shouldn’t be done, and officially by MDG. I’m just trying to make sure MDG really explores this. It’s a non-standard solution to a degree, but that’s what stop-gaps are, and it will work. So with everyone complaining about their dealing with Blaze/React in 200 post long threads, and not speaking up and the few that have moved on to pure React land, like yourself, downplaying it, it’s a problem.
The goal is to get hip to the possibilities, the similarities between React and Blaze. It’s not as different as you might think. It’s hard to describe what the problem is with Blaze–you and I have tried, and basically failed. It just gets tangled, and it’s hard to pinpoint why. The reason isn’t that you can access parent data context or state–you can do that in React very easily, and without losing the ability for child components to update properly; just think about it, you already have the parent props/state, it’s just a matter of passing more of it down to children, which can be done automatically for you; just check the above jsfiddle link in the initial post–the problem is the timer/flush based stuff that Tracker/Blaze does where when too many things are going on it combusts. I.e. where timer callbacks get missed. And it’s likely just oversealous autoruns, all just constantly triggering, even if they aren’t causing a cycle. With their current proposals, we are just going to get more Tracker. Perhaps the problem is Tracker, not Blaze. If tracker is going hey wire doing a million things, it’s going to cause React to constantly re-render too. React isn’t that fine-grained at rendering. It could even be less than Blaze in terms of the pre-virtual-dom updates.
The virtual dom functions as a filter for React, likely doing the absolute most fine-grained dom updates possible. Blaze is likely doing a lot more. That’s where performance counts the most. Perhaps React touches the actual DOM less, but touches the virtual DOM more than Blaze does the equivalent. The latter doesn’t matter nearly as much. In reality, React likely touches the real DOM less AND it has less going on pre dom manipulation. Blaze has tracker going hey-wire pre-virtual dom.
So what I’m saying is this: to blame it all on the flow of data is a cop out on MDG’s part. The “unidirectional” thing does not need to mean developers don’t have an abstraction for them to access parent component data/state parent.
Tracker is a menace. To me, given it simplicity to application developers, a welcome menace though–one that’s optimized primarily by application developers tuning it, e.g: with cursors that only select the fields you need. I do think, though, more specific types of Autoruns could be offered as I provided examples for the other day. They would help box in the variables that trigger Tracker-based reactivity.
We’ll likely be stuck with many of the same issues as long as Tracker is being used–at least without additional types of autoruns that offer fine-grained control and lead you into the “pit of success” of reactivity. Not recognizing the real problem here is going to lead to half-assed output: A) unnecessarily losing Blaze features (its simpler interface) and B) doubling-down on Tracker, which is what might need to be replaced altogether, or at least severely upgraded–that’s where resources may be better spent. So by pretending and sweeping things under the rug, we aren’t truly solving our problems here. But we can at least hope React is a panacea.
Autoruns were a nifty concept. Extremely clever. And the interface for application developers is super duper seamless and natural. It’s the soul of Meteor, and what got us all hooked in the first place. So hopefully the interface doesn’t need to become complex through requiring it to be more explicit, but the implementation may be in dire need of an overhaul. Or perhaps it was just wishful thinking all along. I think MDG has likely found themselves married to tracker at all levels of the stack, and don’t want to face its core performance-oriented pitfalls. Who would? I wouldn’t. Nobody wants to give up a great interface–which to be clear, it is–for more implementation non-sense we all gotta do. But maybe there is a middle way. Outside the box solutions include: Autorun classes that let you define how they will perform + a library of pre-made ones to choose from, a UI in your application to inspect the behavior of all your autoruns (what fields are triggering them, what collections, where in the code, what other autorun they triggered after they run, where they are defined etc). Basically autoruns suffer the “lack of observability” core problem of software programming Bret Victor pointed out several years ago. Deeper insight into our autoruns could be all we need. There could straightup be alerts in this GUI that warn you when too much is going on and you should optimize it, and provides optimization recommendations.
If you’re application’s autoruns weren’t so busy, I’m willing to bet we wouldn’t have any of these problems. So the root question should be: how do we box autoruns in? Not: how do we put them up against a more resilient rendering system, which is what we are doing.
The problem is that the concept of “cursors” wasn’t taken to the property level. Blaze attempts to re-render the DOM even if you don’t use properties on the models you’re rendering. Most developers aren’t optimizing the fields in their find()
options. That means if you have a cron task on the server, for example calculating aggregates, all your clients are going to attempt to re-render model objects that didn’t even implement the field that changed. There’s no reason the properties of objects could also be the equivalent of “cursors,” i.e. they only trigger Tracker-based reactivity if they are used. That in fact is how Spacebars already deals with Cursors. Spacebars does less work rendering a cursor in an #each
loop than arrays. Conversely, we shouldn’t have to use .fetch
on our cursors in javascript code. Spacebars should just be aware its a cursor, whereas standard javascript code return an array. So take that concept to the property level, and they will only trigger reactivity if Spacebars encounters them. And in javascript, you get the standard strings and integers you expect as returns. That way the application’s performance is dependent on developers taking on all this unnecessary code to specify fields to all their finders. The problem with that is the fields you actually require is always changing–it’s just easier to omit the fields specification. And that’s what everyone does–until they get into this tangled mess, or if time provides, and the project is continuing to pay for itself, at the end of the project.
Basically having to specify all the props you pass down from component to child component in React has 1-to-1 parity with specifying fields
in a in a find()
call. Deeply integrating Tracker into React won’t solve that.
Which is why I’m suggesting we get to the root of the matter here before jumping to conclusions that Blaze needs to be thrown out the window. Also, as far as I’m concerned, I don’t care about Blaze. It’s an interface. I like its interface, specifically the components-based version, such as @mitar’s Blaze Components. Whatever is going on behind the scenes doesn’t matter to me, and can be optimized. The data flow in Blaze is the same as React, or at least with some tweaks can match up to React and not break its unidirectional immutable rules. Spacebars, plus defining event handlers separately, plus an enhanced way to specify helpers + events on parent components to manage state in one top level place (rather than do all the busy work to pass them down) is what I want. The latter of which, the current Blaze or @mitar’s Blaze Components doesn’t offer, but is what I’m working on. If you can specify both the helpers and event handlers on a parent component, but they can be used on child components while utilizing the state of a Parent component is a winning concept, specifically if you also have access to the child component’s props
data context. React has you do a lot of busy work to pass all this stuff down. It’s not just data, it’s methods! That’s ridiculous. It may feel good now, but it’s no good. Cluttering up all your template code, which should otherwise be readable by a web designer with functions, and then continually passing them down–that’s not a good interface. It’s not separation of concerns by any means. It’s a stop gap to access state in its proper place because they couldn’t think of a better solution.
So anyway, MDG’s likely current plan for the future of React + Tracker won’t solve problems inherited from Tracker unless we get to the bottom of it, which is “property-level cursors.” And the messed up part, it likely is easier for them to solve that with Spacebars. In JSX, it’s plain JS–they will have to make TJSX which is able to determine what’s a cursor and what’s not. “T” is for “Tracker” obviously. They need a step to be able to examine what a symbol is before rendering it, and if it’s a property “cursor,” register the component as reactively dependent on that property, but then spit out the value it contains. Again, you can’t do that nearly as easy in JS or JSX. I don’t put anything beyond MDG–they’ve accomplished wonders with Meteor, which is why I’m here–so I at the very least hope they are thinking about building their own JSX transpiler that handles this. It’s a natural progression from automatic fine-grained reactivity where you don’t need getMeteorData
anymore, and component methods themselves track their reactive dependencies, TO where the same applies for the properties of model objects. My assumption has been they are considering the former. So they need to take it all the way, down to the property level. Double down on Tracker for real for real, MDG! We do love Tracker, it just needs to be better. And now you have more problems since you gotta do all this in the React world you’re not familiar with. I agree it’s the right decision to go to React, especially since Blaze can completely transpile to it, but you gotta handle the root of the problem while you’re at it.