SIDEBURNS UPDATE: Rendering Blaze 1 to React is looking 100% possible

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.

Can you provide an example package that I can test? Would autoform be one? You’r going to have to ‘quarantine’ an area in Blaze2/React and then use Blaze 1 inside this area… from here you can use autoform like normal.

Yea I’d say AutoForm is the canonical example here–since the interface to the application developer is a custom block helper. Well, there is also quickForm which is used as a standard Template, but all real projects use the block helper form. Here’s the first example of it from its readme:

<template name="insertBookForm">
  {{#autoForm collection="Books" id="insertBookForm" type="insert"}}
    <fieldset>
      <legend>Add a Book</legend>
      {{> afQuickField name='title'}}
      {{> afQuickField name='author'}}
      {{> afQuickField name='summary' rows=6}}
      {{> afQuickField name='copies'}}
      {{> afQuickField name='lastCheckedOut'}}
    </fieldset>
    <button type="submit" class="btn btn-primary">Insert</button>
  {{/autoForm}}
</template>

I’ve never had the need for it, but you probably can do forms within forms for sub documents. And there may be other block helpers that I’m not digging up from the page right now that when used within each other may pose more problems. For sure, if there is custom block helper nesting, this is gonna be something @aldeed will have to do to not make it a bunch of hurdles application developers have to deal with.

I’d love to see how the basic #autoForm example above turns out. I’m sure you will figure it out, i.e. with this.props.children et al, and I’ll concede if that’s the extent of the complexity needed for 80% of all packages, than I may be making a bigger deal out of this than it actually is. It still will be a while before our codebase isn’t cluttered with a million blaze wrappers as stop gaps.

ps. @SkinnyGeek1010 check out what I just added to my previous post. Thinking through these things I just discovered what I think is at the core of the performance pitfalls Blaze/Tracker lacks compared to React! The summary is that specifying fields in a find() options object is the equivalent of specifying which props you pass down from component to child component in React. Blaze goes hey wire because everyone just leaves the fields option empty, and rightfully so for most of development. It’s a pain to constantly be specifying those props, and even more so in React since you have to do that for every child component they trickle down through. What I’m proposing is “property level cursors” (only within templates) that only trigger Tracker-based reactivity if the props are actually used! Similar to collection cursors. That’s the sorta automation React could only dream to have. Anyway, just think about it, Blaze attempts to re-render the DOM for all connected clients every time a cron task updates a field on a collection’s model object, say if various aggregates are being calculated and stored on a single field. Tracker should be silent, but it doesn’t know what properties are being used and which one’s arent. Now, I don’t love Blaze–MDG should do this in React with their own JSX compiler that detects what’s going on within render calls; or perhaps they do it in their Spacebars variant.

1 Like

Blaze Components do offer having state at the top-level component and using that state. You just get a reference to it and use it. It is just how you structure your component tree. Blaze Components do not require or predefine any of that, but it also allows and empower you to choose whichever you prefer.

See this ticket for more information.

I’m not seeing. How can yo do the equivalent of this:

<template name="ParentComponent">
    <h1>SELECTED CHILD: {{selectedChildName}}</h1>
    {{#each posts}}
        {{> ChildComponent}}
    {{/each}}
</template>

<template name="ChildComponent">
    <button />
</template>


class ParentComponent extends BlazeComponent {
   onCreated: function() {
       this.name = new ReactiveField('n/a'); //aka in react: `this.setState({name: 'n/a'});`
   }
   selectedChildName: function() {
         return this.name();
   },
   
    events() {
      return super.events().concat({
         'click button': this.onClick
      });
  }

  onClick() {
     //event is triggered on child, but state is the parents.
     //the data context is the child component's. 
     this.name(??this.name??); // `this.name` usually is the data context, where is it?
  }
}

Can yo do that? Will that work?

I assume you can–my next question is can your helpers work in the Child component? That’s key for the combination of event handlers + helpers to be effective in like 50% of all scenarios. For example (and this time I won’t use ReactiveField since I’m not sure where the Data context is):

<template name="ParentComponent">
    <button class="expand-collapse" />

    {{#each posts}}
        {{> ChildComponent}}
    {{/each}}
</template>

<template name="ChildComponent">
   {{#if expanded}}
       <h1>{{title}}</h1>
       <p>{{body}}</p>
   {{else}}
         <h1>{{title}}</h1>
   {{/if}
</template>
class ParentComponent extends BlazeComponent {
   onCreated: function() {
       Template.instance().expandedIds == new ReactiveVar([ ]); 
   }

   
  events() {
     return super.events().concat({
        'click button': this.triggerExpandCollapseAll,
        'click h1': this.triggerExpandCollapseOne
     });
  }

  //helper on parent
  posts() {
     return Posts.find();
  }

  //helper on child!! ..the point is it needs to share the state of the parent.
  expanded() {
     let ids = Template.instance().expandedIds.get(), // in my "Blaze Components" I have simply: `this.get('expandedIds')` since `Template.instance()` won't work.
     return _.contains(ids, this._id);
  }

  triggerExpandCollapseAll() {
     let ids = Template.instance().expandedIds.get(),
         allIds = this.posts().map(post => post._id); 

     if(_.isEmpty(ids)) Template.instance().expandedIds.set(allIds);
     else Template.instance().expandedIds.set([ ]);

  }
  triggerExpandCollapseOne() {
     let ids = Template.instance().expandedIds.get(); 

     if(!_.contains(ids, this._id) ids.push(this._id);
     else ids = _.without(ids, this._id);

     Template.instance().expandedIds.set(ids);
  }
}

So this is how my Blaze Components works–helpers are inherited automatically (and dynamically) by child views at render time, while keeping the state from where they were defined. In that example, the state is needed on not just the parent, but also the child. And specifically within helpers. So that means the helpers must be automatically inherited by children. I checked your lookup.js file, and you don’t check the chain of parents for helpers that match–though, there could be other ways to accomplish this.

Event in the first example will trigger on the parent component. But in this case the code in Blaze Components would be:

onClick(event) {
  this.name(this.currentData().name);
}

got it!

…i figured that must be possible with yours. what about the second? how do you propose state is shared between parents and descendants when it comes to helpers?

Again, Blaze Components are trying to provide minimal API to allow you to have then your preferred way implemented on top. Even I do not use bare base class myself, but have extension build on top of it.

So the design decision was to not provide such automatic inheritance because some people would not like it. But it is easy to add it if you want. Or easy to create methods to allow you to do that.

How I would do it is implement on child component the expanded helper:

expanded() {
  let ids = this.callAncestorWith('expandedIds');
  return _.contains(ids, this._id);
}

(Here I assume use of ReactiveField.)

How I see it is that ParentComponent provides public API expandedIds, which then child components use for their need.

This allows much more modular code. Why would expanded be somewhere else, when it should be with the component which uses it.

That’s not a bad approach. My questions are:

  1. what if you re-arrange the templates, and nest your code in more child templates–how does it know which ancestor to reach up to?
  2. suppose it’s programmed to reach the first ancestor that has the ‘expanedIds’ key (solving problem #1), what if it collides with other properties? I’d say this is sub-par compared to helpers maybe colliding: since helpers are static and more obvious since they are usually static members of a class prototype, whereas state keys can be dynamic–who knows what keys are dynamically added at run time? State keys are also more buried in code.

So, if we are just to accept #2 and #1 is solved by your system, here are the pros and cons of both approaches:

CALL ANCESTOR APPROACH:
PROS:

  • helper with component that uses it.

CONS:

  • more potential for inability to access parent state
  • extra call to get access to state. it’s available by default.

HELPER DEFINED ON PARENT APPROACH
PROS:

  • helper with component that implements other methods related to the state! (it’s subjective)
  • matches the React pattern of passing functions down–just automatically in this case
  • enforces “state management strategy”–helps you think about where you want state to live, and unlike React makes it very easy to pick that place, and just start writing your methods there, rather than passing them down, or in case of the “ancestor” approach reaching backwards.

CONS:

  • may require more time to wrap your head around, just as passing functions down does in React. For some it’s more natural to put methods on the child component and then ask for state than to consider state as a given and pass your helpers down

The main thing though–is you aren’t “passing your helpers down.” That’s React’s problem. In the “Helper Defined Parent on Parent Approach” above it’s automatic. It’s natural dynamic inheritance or whatever you wanna call it. So it’s a given that all work you previously did on parent components you have available to child components (i.e. their helpers and event handlers). That’s automating lot for developers, while of course guiding developers seamlessly into the state management pit of success. Whereas in the first approach, state management ends up being an after thought. You are more likely in that one to be in the scenario where you now need to move your state up a level so the parent can have an “expand/collapse all” button, whereas in the second approach, you are likely to have already defined your state-related methods on the correct parent. The reason is because templates get dumber and dumber the deeper they are nesting–we are used to treating higher up components like controllers anyway. In addition, you start by coding parent templates/components. You will likely first implement many methods on these higher templates in their first form before moving down to child templates. It’s not only very nice to have those methods available to you as compose in smaller and smaller nested templates, but the state is also very often already where it needs to be! I.e. the perfect parent component who is the first component that composes all the children that access the state.

And here’s the clincher: basically, if you continue to compose your templates of smaller and smaller nested templates, which is a common refactoring process, then you need to move your helpers too. You never have to do that with the helper inheritance approach. Compose into smaller more organized nested templates all you want! I do this all the time. I have many dumb templates, which I make so the messier parent templates become cleaner and easier to reason about again. But if you do this with the call the ancestor approach, you have to go back and change the js for where its helpers are defined as well. You have to assign them to a different template now, perhaps move them to another file. And there’s more: events are already “inherited” from parent to child component. So it’s a mental mismatch between how helpers and events work. If they both worked the same, that’s one less thing developers have to factor into their reasoning. And that’s where the perfect marriage of the “Helper Inheritance” approach occurs–they both behave the same way and channel state to the perfect parent, while automatically doing everything else for you, solving the problems of both React and Blaze (fireworks, shooting stars, etc). I’m not gonna go back and change the pros/cons list above, but there are now many more in favor of the helper inheritance approach.

It’s basically just like looking at React the first time, and being frustrated. It’s a paradigm shift–though here to a lot lesser extent–but once you get over the first hump, you begin to see all the additional benefits. I know you were trying to stay more true to standard Blaze–I love your Blaze Components. That was a good strategy to make it more seamless to move over for existing projects, and a big inspiration for what I’ve been formulating. The route I have taken doesn’t care as much. It’s for new projects. So I’m just trying to figure out the absolute best path forward, having spent a lot of time having completely fixed Blaze (even if it’s too far of a departure from Blaze for old projects), and now trying to factor in how the React fiasco fits. Fortunately, it’s shaping up quite nice. The “Helper Inheritance” interface I already have is matching up perfectly with React.

Here’s the revised version of the previous class in my style fyi:

class ParentComponent extends Meteor.Component {//onCreated not necessary
  posts() {  //helper on parent
     return Posts.find();
  }

  //helper on child!! ..the point is it needs to share the state of the parent.
  expanded() {
     return _.contains(this.get('expandedIds'), this._id);
  }

 'click button'() {
     let ids = this.get('expandedIds'), //basically `get/set` handles state behind the scenes (i.e. `Template.instance()`
         allIds = this.posts().map(post => post._id); 

     if(_.isEmpty(ids)) this.set('expandedIds', allIds);
     else this.set('expandedIds', [ ]);

  }
 'click h1'() {
     let ids = this.get('expandedIds'); 

     if(!_.contains(ids, this._id) ids.push(this._id);
     else ids = _.without(ids, this._id);

     this.set('expandedIds', ids);
  }
}

For a developer who is developing for developing sake, there might be no reason. But for the rest of us, who have invested in the Blaze technology and want to focus on business value, any smooth upgrade path is very welcome. So I am glad that @faceyspacey is developing this.

I don’t get it, you can replace your app one small part (as small as a button) at a time and slowly refactor over time. You really just cannot sit down for 10 min (not even) and learn react?

3 Likes

The callAncestorWith searches for the first ancestor with expandedIds property. You can safely reorganize the code. You can also decide that you have all the state in the top-level component.

You can also imagine some other ways to traverse the tree and search for wanted component instance. For example, one other common pattern I am using is to search for an ancestor component instance which is an instance of a particular component class.

suppose it’s programmed to reach the first ancestor that has the
’expanedIds’ key (solving problem #1), what if it collides with other
properties? I’d say this is sub-par compared to helpers maybe colliding:
since helpers are static and more obvious since they are usually static
members of a class prototype, whereas state keys can be dynamic–who
knows what keys are dynamically added at run time? State keys are also
more buried in code.

That is the question of your code structure. You could have your public API of your component be attached to this.public. You could have all dynamic properties which should not be public prefixed with _. It is really left to you to decide how you want to do that.

I think it is of similar complexity to how to assure that components do not clobber its own helpers when you automatically inherit them through the components tree. I prefer explicit traversal of the tree though (because you can control it more) than one where you automatically inherit and the only condition on which you can match is symbol/property name.

Again, it is on the developer to decide how they want to use that. They can put all helpers on the top level and then know nothing will be clobbered. Or they might even want to clobber something on purpose (to override/extend it).

What I am saying that you can with Blaze Components decide for both approaches, as you prefer.

I see how you can move state to controller parent. Just now, you gotta explicitly call to your ancestors every time you need some help, but I get it. With stuff like calling an ancestor of a specific type, it’s a little bit complex, but pretty solid. I. Both at the end of the day are very similar. My goal was just to fully understand how your system works, its intent, and the best way to use it. I understand it now. I mean basically Meteor developers needed to be doing this sorta stuff for a long while now. And we need to insure the new component architecture put forth by MDG (or our wrappers) takes into consideration the ideas we’ve been throwing around. We both have our preferences, but I’ll tell you this is for sure: my preference is not passing down every damn event handler function and helper method return to child components like in React! It’s unnecessary and can and should be automated. It doesn’t violate the unidirectional flow. It only slightly violates immutability–since you need references to parents. But in the most harmless way possible. That reference behaves like immutable data flowing through the system–i.e. it changes to a new reference when the parent changes. MDG won’t have the balls to modify React that much is my guess, but someone’s gonna have to if we want this done right.

whats your plan? a react component inside a blaze component inside a react component inside a blaze component?? You want to write wrappers like the above loginButtons one every step of the way for the next 1.5 years? The problem is bigger than having to “learn react.” I know React very well, and this is a major problem for me given how much Blaze code across many projects I have. How many Meteor projects in production do you have? I can barely imagine even going in there putting some react code in the midst of all the Blaze code. …I mean where do you start? You basically should start with React as the wrapper for everything–so then, what, you render your entire Blaze app in React. Where do you start eating away at the Blaze? Picture a basic website, one column is blaze and the other is react, while react contains them both??

There’s no answers to these questions. It’s not pretty like you think. And for sites already in production that you’re now ripping apart, and throwing the same stuff up together in hacked form to get access to like one React thing. It basically makes no sense, and the reality is the majority of these projects will never make it to the next React round. React Meteor will be for new projects. And that’s just gonna be the reality for the vast majority of cases. You’re either Blaze or React. Doing both isn’t gonna be a common practice, my friend. The only time it will happen is in new React projects that want to cherry pick one or 2 legacy Blaze packages like the login buttons. That’s it my friend. IN SHORT: NEW PROJECTS. I’d go study and use Phoenix for the next 8 months until Atmosphere isn’t package poor in terms of components compatible with React.

There’s a plethora of amazing stuff for Blaze, specifically for Blaze coupled to Meteor that won’t exist for a long time for Meteor + React, even if it’s just minor wrappers that must be implemented. If you can start out on a fresh tinker project with React + Meteor, it’s not as much of a problem. U will still find yourself needlessly writing wrappers for what was simple plugins–not a good feeling! However, for your troubles you may now get access to the React ecosystem, but you have to understand these packages are just view packages. Packages that couple the entire Meteor stack are a lot more powerful. We want these packages. They exist already. They will all have to be upgraded. In practical terms, professional developers are gonna stay away from all this mixing and matching. Sending both React and Blaze libraries to the client–that’s jus the beginning of the troubles. We are all gonna veer away from this option, and cheery pick as last resorts.

Actually, I just recently slowly refactored a 1 year old project from blaze to react.

You start from the bottom up. You replace the bottom of the components tree and and once all the components that shares the same parent are converted, you convert the parent. You traverse like these until you replace the top most component.

Meteor already offers {{> React Component}} so this is very simple to do. There is no react wrapping meteor because you are replacing all children before the parent.

Also, no one has time to read your wall of post.

2 Likes

Thanks! i’ll use this as an example and spike something out this weekend. I’m currently using TabularTables in a React app and that’s also using the configs for the client/server and collections, etc… However, that might be too simple of an example (though more involved that loginButtons). I forget exactly what I did but you have to pass in the opts into Blaze a different way and also when passing in a function it has to handle it a bit differently such as:

{{#someHelper id="foo" name=somFunc }}

If i’m remembering correctly Blaze implicitly calls the function where as React does not, though that would be easier for MDG to handle :smiley: I think I had to work around it somehow in the adapter.

ps. @SkinnyGeek1010 check out what I just added to my previous post.

I’ll checkout this later as well.

1 Like

R u still here?

…so you opted for many React islands? How’d that work out for you?

The only thing I see wrong with that is the absolute #1 reason to move to React is to get access to React Native–that’s a long time before you get access to React Native. I guess it would be that way either way–since Blaze likely gotta be all gone by the time you get to React Native land.

TabularTables is another perfect example, but for a different reason: it’s a package that does work on both the view layer and on the server. I.e. stuff you’re not going to get from React addons. It signifies why it’s so important we make this as seamless as possible: it will harm our access not just to the view, but solutions/abstractions we’ve been using on the server as well. There’s a lot of tightly coupled Meteor + Blaze packages. And we get a lot of power and automation out of that coupling. Anyway, you get the idea…

1 Like

I mean I dont literally start refactoring small things… You can replace at least half part of a page really easily. It’s almost 1 to 1 mapping from blaze to react.

getMeteorData -> tracker, onRendered -> compDidMount, onCreated -> compWillMount, Reactive Vars -> getInitialState.

My app has been fully converted, the factoring peroid was like 2 months, but i was also making new pages using react too, if i was just refactoring old old it would have taken me even less time.

Reactive Native is definitely a big factor for leaning react. I have heard from multiple experience IOS devs telling me react native is just about everything better than developing in Swift/Objective C.

The thing i also absolutely hated about old templating system is the constant switching between two files of html and js, and they are “magically” connected, you end up bug fixing for hours to realize you spelt something wrong. If i spelled anything wrong i will know where exactly the error traces to in react. Even better when using webpack imports. But that’s just me tho.

1 Like