"Deep Tracker Integration" for React Today!


#1

Hey all, James from the Sideburns project here. I got some exciting features from Sideburns we are making available today for React!

A lot of what we’ve been building is extremely effective for React on its own, and since fully rendering Blaze 1 may take a while longer, @timbrandin and I decided it would be a good idea to start releasing parts of the Sideburns project now for React. These are likely some of the core features that @gschmidt and @evanyou hinted at would be in the future official Meteor-enhanced React package–so we figured we’d pave the way for what we want it to look like, and perhaps save them some time.

So without further ado, here’s the TrackerReact mixin you can add to your React components today:

meteor add ultimatejs:tracker-react


https://atmospherejs.com/ultimatejs/tracker-react

And here’s a quick glympse to beam you guys the general concept:

App = React.createClass({
    mixins: [TrackerReact],

    title() {
        return Session.get('title');
    },
    render() {
        return (
            <div>
               <h1>{this.title()}</h1> 
            </div>
        );
    }
});

Badaboom bada bing, it works lol. Just like you expect. With the super declarative, automated, built-in reactivity we’ve come to depend on, and likely take for granted until React came into the picture. This simple enhancement should ease a lot of pain in making the switch.


##INSTANT EXAMPLE APP:
Here’s example app to see it all in action with just a few commands:

git clone https://github.com/ultimatejs/tracker-react-todos-example.git
cd tracker-react-todos-example
meteor

##WHAT DOES IT DO?
It’s essentially an upgrade to what ReactMeteorData offers. It’s “method/helper level reactivity” rather than having to freeze all your reactivity in getMeteorData. This seemingly small adjustment brings you a lot closer to the automated reactivity you have come to know and love in Blaze. A lot of benefits do come with it:

  • any method you want is automatically reactive.
  • you can specify methods you don’t want to be reactive by prefixing them with an underscore _, and your events go in a map returned from the events method. Lifecycle handlers are obviously prevented from being reactive as well.
  • each method runs in its own autorun, so that they aren’t all re-run together.
  • you no longer have to refer to this.data.foo to get your data. You can refer to this.foo() to get it, which is symmetrical to what you are doing in Spacebars.
  • not all your reactive sources need to run if they are not called at run/render time-for example, if they are in an if/else code path not taken, which mean your component is forced to update less.

I’m sure you will find it a nice addition to your React(+Meteor) development experience. Keep in mind it’s brand new. We are releasing it in part for you to find something wrong with it, edge cases, etc. Try to break it! That way we can get these parts solid so by the time Sideburns (“Blaze React”) is done, it will be closer to true completion and ready for primetime. But that said, these features and future features we’ll release are being built to standalone as welcome additions to your React workflow. We have a few things unrelated to Sideburns we’ll release as well. So don’t tag this away in your brain just as things related to keeping your old Blaze 1 code useable. That’s one goal–the second is making the ideal React package for Meteor; and likely in cooperation with MDG as well, i.e. to achieve similar stuff to what @gschmidt said was on their roadmap the other day.

Anyway, that’s all for now. Give it a run-through, use it, break it. Thanks in advance for helping us bridge the Blaze world we know to what will be a delightful React future. Long Live Meteor! Stay tuned for more coming out of the Sideburns and Blaze React project. Pull requests welcome.

-James


##…MORE FOR THOSE INTERESTED:

So some concern has been raised that this is not “The React Way.” Well, that’s not true. It’s called "Sideways Data Loading" and it’s exactly what getMeteorData already does and is working its way to becoming a first class API built into React: https://github.com/facebook/react/issues/3398 .

In short, it’s just state that comes from outside the component, LIKE RELAY, and isn’t assigned to the state key. State itself is basically just “sideways data” that originates in the component itself. It’s important to recognize what’s really going on here. It’s not often that your root component is passed the entire state needed to trickle down the entire tree purely as props. In fact, it’s like never. Data/State must be accumulated along the way somehow.

When you research react more, you begin to see it’s all about the forceUpdate method used internally, and by mixins like this one and ReactMeteorData. React tries to guide you into using it sparingly. It’s mainly meant for library code, whereas to application developers it all feels automated. But in short, React forces a component to update when it wants to, and only the children of its branch are potentially re-rendered; the rest of the tree stays untouched. With pure child components whose props haven’t changed, the operation is extremely fast–that’s why state management is such a big concern in React. It gives you deep control of your rendering performance. But at the end of the day, the mechanism is easy:

  • state map changed, forceUpdate with new state.

In our case it’s:

  • autorun tells us reactive dependencies have changed, forceUpdate + return the new data from utilized helper methods in render call.

With that said, you’re going to want to be more careful with React than with Blaze with how many helpers you use. In fact, rather, you have the opportunity to be more careful with React. In Blaze you don’t have this opportunity, and in part, that’s why Blaze performs so poorly–it’s constantly doing background work to see whether it needs to manipulate the DOM, often without even manipulating the DOM, and possibly triggering side effects if your helpers aren’t purely accessing reactive data sources, i.e. if they change a global variable. …So, in React, you could be forcing updates every which way, across the whole tree, and likely React will render/perform just fine, just like Blaze performs fine most of the time. It’s my opinion that developers are essentially brainwashed into being scared to do the slightest thing that triggers additional updates, god forbid call “forceUpdate” myself! The reality is you can throw a hell of a lot at React and your app will perform just fine.

THE CONCLUSION: make use of this automation to enhance your development flow, and when you feel its time to optimize, reduce the # of calls to the same data sources (Session variables, cursors, etc) to being in one place near the top, i.e. the highest parent component that requires it, and then pass it down as props. That way you don’t have the same portions of the tree forced to update multiple times. In fact, this is a feature @arunoda made available via additional syntax to Blaze with Blaze Plus. The only difference is in React it’s a first class operation that’s standard practice in your workflow. In Blaze (Minus) if you do the equivalent of forceUpdate at the top of a branch, i.e. pass down reactive data sources from parent templates, templates unnecessarily re-render. Whereas, in React child components only re-render if they implemented a changed prop. It’s a lot more finegrained.

So in the context of using TrackerReact, by moving your state–STATE COMING FROM REACTIVE HELPERS–to the top, and passing down what’s needed, you reduce rendering work. In Blaze, you can’t move reactive data sources to the top (instead of in the helpers of child templates) without a lot of re-renders. I point you to @arunoda’s Blaze Plus for more information on that: https://github.com/kadirahq/blaze-plus. I also urge you to start a React app example, and add componentWillMount, componentWillUpdate and other life cycle handlers to your component, filled with console.log to see when everything triggers, and then call setState() from the console to compare it to blaze’s corresponding handlers. You will have to assign your component to something like window.COMPONENT in the componentWillMount handler so you have access to it from the console.

###FINAL THOUGHTS:

All this brings me to my final point: Blaze’s real problem is Tracker. Tracker is constantly in the background, often going hey-wire. It’s running autorun functions non-stop essentially. Say you have a cron job that updates an aggregate field on a collection object–well all connected clients will unnecessarily re-run helpers that are currently returning that object or cursor that contains it. You may say, well use fields. But the reality is the following:

  • you guys find it a nuisance to pass all these damn props down all the time in React, right?
  • well, passing props down has perfect parity with the purpose of fields in your find() calls:
  • it limits how often your components have to update!
  • we often dont use fields so we don’t have to constantly do this extra boilerplate work.

The reality for many developers is it’s not until the end until you optimize fields. Most projects are lucky to have the resources to fund/maintain it to this point.

What both Blaze and React for Meteor needs–you heard it hear first–is: ***“property level cursors”***. We are working towards a future where you can call this.subscribe in your React component, benefit from the automation of “method level reactivity,” [a few other yet to be mentioned things ;)], AND use Spacebars! What the Meteor + React needs is a feature, at possibly at the Spacebars transpiler level, to tell the find cursors what props are actually used, and automatically fill those in as fields. That will greatly AND AUTOMATICALLY limit the amount of component updates.

What I’m also saying here is this: MDG’s announcement the other day didn’t get to the heart of the matter and in fact made some misconceptions. The misconception being that it’s not possible to render Blaze 1 automatically to React and you’ll have to [manually] “port” your code:

Interpretation: you will have to do work on all your packages to make them work in the new React-based future. It won’t be automated.

In the coming weeks, Sideburns will disprove that. And I’m going to incrementally roll out the constituent features for React, as I’m doing today. That said and for what it’s worth, it’s my guess MDG made this announcement in response to all the pressure we put on them regarding React in the initial thread @mitar started. And they then made this announcement before they were fully informed, just because they felt they had to say something. I really wouldn’t take that announcement too seriously–just to empathize with them: they’re in a tough situation; they’re like 4 years in, probably having burnt through more money than they would have liked before generating a cent, and they finally have their cash cow ready (Galaxy), and likely it’s the biggest technical feat of all the engineering they’ve done; and now all they can think about it is making it pay for itself so they can even continue providing us these awesome tools to begin with! For all we know, they’re insulating us from how close they are to having to close shop if Galaxy doesn’t turn a profit and quick! See what I’m saying. Anyway, the people that know the most about React are–um, the fine people over at our now biggest competitor lol, Facebook, who built it. So that’s not MDG. There’s a lot we all have to learn about the new React world. I wouldn’t count on any one person within the Meteor community or MDG itself knowing everything about it yet. React is shaping up to be a lot more flexible than you might think–and very likely flexible enough to render Blaze 1.

NEXT: I’d like to get back to the changes I think MDG, and really the whole community, should focus on, instead of just Blaze 2 in React Form (on a side note: nobody has to, because I’m basically already gonna do it for you guys).

…Ok, so, the “heart of the matter” is that the real problem with Blaze is Tracker! It’s constantly updating as I’ve said. Autoruns get tangled, etc (I’m not just talking “helpers” anymore). I personally think it’s a necessary evil, given the declarative automation it provides, but it brings along some challenges; challenges that MDG has failed to address or possibly even recognize. In terms of Blaze, the renderings keep happening because there is no “property level cursor.” What would that look like–this:

Posts.find().map(post => post.title.get())

instead of:

Posts.find().map(post => post.title)

However, in javascript you never type out that operation the first way, you always perform it the second way, BUT IN SPACEBARS (OR JSX) the transpiler generates code that looks like the first way! The information of what property cursors were used somehow works its way “backwards” to where you made the initial find() call an automatically specifies the fields option for you. Now the TrackerReact mixin (i.e. what was launched today) will call forceUpdate on components far less. In terms of Blaze, if Blaze had this, it will perform a hell of a lot better as well. We need to find a way to make the helper autoruns stop running when they aren’t needed! That’s the challenge, and this is the solution. That problem isn’t magically solved by moving to React. Solving this needs to be a first class priority just like the “reactive revelation” via autoruns was for the founding MDG team.

That will solve helpers, but we also need to automatically optimize our autoruns that we create outside of helpers. To do that we need different classes of Autoruns. Essentially an Autorun class or object we can define which lets you set various properties that configure the circumstances within which it will run, e.g. only on a certain route, with certain params, eg. for a certain user role, if dependent subscriptions are ready!, if certain session vars are set, etc. We need as many ways to box in our Autoruns as possible, to keep them from being triggered in response to imprecise dependencies. Tracker needs to become more fine grained just like how React renders components/templates in a more fine grained manner than Blaze. Again this is Tracker work. We need to invest in taking Tracker to the next level.

I got a lot of stuff to release for React in the coming weeks that will make the "Connected React Client" feel like butter for Meteor. What’s likely outside of my capabilities is “property level cursors.” Now, I don’t even know if it’s fully possible–but with enough elbow grease almost anything is; and the point is “property level cursors” is worth it for the aforementioned reasons. So it’s these Tracker upgrades that I suggest should be the focus of MDG’s upcoming client side work. “property level cursors” is likely a mission, whereas what I’m doing is basically the obvious next steps for React+Meteor if you spend time thinking about it. Anyway, that’s it for now, look for React to become more awesome week by week.


Next steps on Blaze and the view layer
#2

Haha love the enthusiasm!


#3

I have one issue with this - what if I define a model that has a reactive helper on it? For example:

const myObject = new ReactiveVar(1);

Component = React.createClass({
  mixins: [TrackerReact],

  render() {
    return (
      <div>{myObject.get()}</div>
    );
  }
});

// Will not cause a re-render
myObject.set(2);

This is actually the biggest issue we’ve run into with the getMeteorData approach - it’s easy to accidentally access reactive data inside render and expect it to work, since this style of code actually works great in Blaze.


#4
App = React.createClass({
   componentWillMount() {
	this.foo  = new ReactiveVar(1);
    },
    foo() {
        return this.foo.get();
    },
    events() {
        return {
           changeFoo: function() {
               this.foo.set(prompt('What do you wanna change foo to?'));
	   }
        }
    },
    render() {
      return (
        <div onClick={this.changeFoo}>
           {this.foo()} 
	</div>
      );
    }
});

the reactive var could also be defined globally like in your example, and then you assign the global to this.foo in componentWillMount.

It’s not very different than how you would normally assign such things to Template.instance().

So the caveat currently is that you must proxy through a helper method. But I do wonder if we could make render directly reactive as well. We likely can. That seems to be all your asking–how can we use reactive variables from outer scopes directly in render?? I’ll give that a try later.


#5

That’s exactly right. We’ve definitely encountered bugs in real life where someone forgot to proxy a reactive data source through a “helper”. I’d love to see an experiment with making render reactive.


#6

awesome, coming right up!


#7

I’ll make a couple of other points as to why you should just wrap .render() for this approach:

  1. I’m not sure what the purpose of creating one autorun per helper is? I mean:
    a) what if you call the helper twice with different arguments? [1]
    b) all helpers are going to re-run anyway on forceUpdate(), so what exactly does it achieve?

  2. If you instead simply wrap .render() you don’t need to maintain a list of “non-wrapped” exceptions (like componentWillMount) on the component (which is surely going to be incorrect once you factor in other mixins…)

Note also that also some of this issues with our current implementation will still apply. Primarily this one: https://github.com/meteor/react-packages/issues/136

As an aside, I personally agree, especially when you look at this PR, that it appears that React are moving in this sort of direction for side-loading[2].

[1] (The first autorun gets destroyed and becomes non-reactive, is what happens.)

[2] Honestly, it feels kind of un-React-y to have things re-rendering without it being clear why from props, state, and maybe data though. I guess we’ll see if that PR gets merged…


#8

The first one is destroyed like you said, and replaced with a new one. So variable arguments works.

The main achieve meant is that if the initial render call executes a code path where the helper is NOT used it won’t give the component the opportunity to track the dependency, and perhaps may never become reactive. Whereas if the reactive dependency is tracked on the helper level, it’s given another chance to update. Now, the current implementation doesn’t actually achieve that since the helper method isn’t called, and in turn track the dependency, if it’s not used–but essentially you’ve pointed out an easy upgrade to make: call all helper methods on componentWillMount to make that initial dependency connection, even if they are in fact not used. The net result is the expected result you’re shooting to have from finer-grained reactivity: a lot less tracker computation restarting. This becomes especially important when you consider that the component can be updated from many other non-reactive React-triggered places: parent component re-rendering, other mixins forcing updates, etc. Combine that with a feature to memoize the helper’s arguments and not create new autoruns if the arguments are the same and if the method is being called by a react re-rendering rather than a reactive dependency changing, then we have a lot less autorun re-creation.

That said, we are now backing every helper method with an autorun vs. just the one, i.e. render, which is more work to begin with. But my hunch is in the long run we’ll discover it important for our components to have knowledge of individual dependencies beyond just a single computation as we do now. And even though a single computation has knowledge of all dependents, i.e. as is clear in the _onInvalidatedCallbacks key of the computation, it doesn’t make the connection to the exact code that needs it. I expect that to become important for other reasons as well, even if various performance tests debunk my point above, i.e. prove that a single autorun backing render is more performant the majority of the time compared to the combination of non-executed code paths + argument memoization + react-triggered re-rendering = not unnecessarily re-creating autoruns.

Since when is more information less good–only when we don’t have the tools to harness it, or the cost of maintaining it is higher than the benefits it provides. At the end of the day, the goal for all this is to bring it lower and lower level like you basically suggested with that PR. I think if we can get the model right at the top level in terms of expected behavior–even if it’s somewhat hacky–then we will be inspired to tackle the robust “deep integration approach.” For the stage we’re at, I see the goal as attaining “deep integration” in terms of the interface offered application developers. We can tackle our own “deep integration” at the implementation level when meteor developers prove they like it.

For now, I have to figure out if I’m just gonna move to the render approach like you said or figure out how to not tangle things given that now helper method autoruns are running within the render method autorun. That wouldn’t be so complex, except the original getMeteorData implementation says something about the possibility of a 3rd global autorun wrapping the whole react component tree. So at this very moment, I’m not sure how to backtrack up a tree of autoruns.

I didn’t actually need to do that. Multiple life cycle handlers can exist per hook–React internally gathers and orders them elsewhere; methods for hooks don’t even exist on the instance object. Most the other exceptions in the regex you can just detect on the the ReactClassComponent prototype. I mainly kept the regex in there for documentation for anyone initially looking at it.

I’d say integration with Meteor lays at the cross-section between the React way and the Meteor/Tracker way, and given that they are totally toying around with these concepts (“sideways data-loading”), I think it’s the perfect opportunity for us to innovate here, and we shouldn’t be bashful. The whole frenzy React has everyone in about making sure never to re-render and update more than you need to by perfectly passing props down from pure component to pure component isn’t productive, not for developers providing the necessary integrations at least. After all, what is Relay or anything doing to get the data into the component. So my conclusion is for now we get this done with essentially Tracker hacks, and then when React releases first class APIs for it, then we switch it to that. Or perhaps use code from the PR you listed today for deeper integrations, and likely solve things like the bug you mentioned, which is happening primarily because we aren’t integrating at deep enough level.

The point is we hone in on what this interface really should be, top down, and then optimize the implementation details

…I’m glad to know about bugs like that, but we shouldn’t be too worried about them yet, especially since they may solve themselves as we integrate deeper and deeper with React’s task queue instead of Tracker’s. Perhaps I wouldn’t even know about react’s internal queue until you posted that bug lol. But anyway we need to carve out what this whole React Meteor Component interface looks like first before we get to such optimizations.

class MyComponent extends Meteor.Component //an interface like this perhaps? 

My next goal is bringing meteor’s event selectors to React, rather than having to pass down and assign event handler functions. Personally I think that’s retarded, and I’ve done preliminary tests http://jsfiddle.net/s5823g2w/1 to determine it doesn’t have to be that way. It’s one of the things that Blaze got right that React didn’t–and you’ll see very soon what other ingredients I add so you keep the same state management magic React excels at. This also seems to be the biggest hurdle for people coming from Blaze to React or newcomers to react in general–“what the hell is this pass functions down thing?” is their number one question. And it does take a while until you finally get it. So that’s sure to be a welcome connection back to the Blaze world meteor developers already grok, and will further define what our component interfaces are supposed to look like. At the end of the day we want the perfect combination of @mitar’s Blaze Components + React Components + Tracker. And if you look at the above interface with Meteor.Component you’ll notice we have an option to step farther away from plain React–and I think we should. It could also be achieved using a regular react component and stuffing it full of mixins, but that’s not the Meteor way, that’s bad for branding, that’s just more work for developers. The point is we don’t necessarily customize React so much that we are no longer react, need to constantly merge in React updates to our fork, etc, but we present it as such with a nice sheen and facade that we are something more yet simpler, i.e. what’s always been the Meteor value proposition. Our components need to be feature packed (this.subscribe(), etc, eventually a Mongo relay-style ORM), and in a few keys areas do things slightly different than react: tracker altogether, event selectors, and dynamic helper inheritance (similar to what’s going on in Blaze’s lookup.js file) so event handlers operating on child components can connect to the same state as helpers currently in scope (by bringing parent component helpers into scope). That’s what Blaze has needed all this time, which is beyond what Blaze Components is capable of. Meteor React Components is the place to do it while bringing along event selectors Meteor/Blaze developers know and love.


#9

Actually it doesn’t, if the helper has different dependencies depending on the argument, then the first call will not properly invalidate. I can send you a repro if you want to see it.

And what’s bad about that? I’m super confused about this statement. How could you evaluate a helper that takes an argument without knowing what the argument is?

I think maybe a simple approach is that if people want to improve the performance of their components (i.e. avoid “re-rendering too often” problems), they can use shouldComponentUpdate or a computed field.

Personally I’m an advocate for wrapper components where the “smart” component uses the reactive data sources (and doesn’t really do anything but fetch data), and the child “pure” component simply renders based off that. Then you can use shouldComponentUpdate to your hearts content in the child if you want to get performant.


#10

We’ll have to agree to disagree on this one. Event handlers reaching into child templates has got to be the biggest problem with the current Blaze API in my opinion. Making it difficult to pass event handlers into children (a much better way of communicating between components) is another (related) one.

I think React got the “data goes in one direction through the hierarchy only, apart from callbacks” thing exactly right. It’s a little restrictive, but sometimes constraints actually help you in the long run.


#11
callReactiveHelperMethod() {
    return Session.get('foo');
},
render() {
   if(false) { //obviously the value of false is a dynamic variable
      let foo = this.callReactiveHelperMethod();
   }
   //return whatever

That render call won’t know to reactively re-render.


#12

well, having a parser automatically make the attachments for you is identical to manually doing it. The problem is what Blaze is missing that doesn’t let you make full use of the pattern (and thats where you end up getting yourself into trouble–not just purely by having jQuery style event selectors). What blaze is missing is access to the state of the parent component that defines the event handler from helpers called in the child component.

So what Blaze 1 has is essentially event handler dynamic inheritance from parent component to child component, right. I’m proposing that we also have helper inheritance to match up with it. AND then in both cases fix the issue of what Template.instance() or state refer to: it doesn’t refer to the state of the template/component that the helper/handler runs in, but the dynamic parent one it was defined in.

The net result is the exact same benefits you get in React: being guided into the “pit of successful state management success,” but with more ease/automation, less friction. The workflow becomes:

  • define the helpers and event handlers on the component that manages the state
  • DON’T WORRY ABOUT PASSING DOWN EITHER THE EVENT HANDLERS THAT ACTS ON THE STATE NOR THE HELPERS/DATA THAT PRESENTS THE STATE
  • simply call the corresponding helper methods in child components.

That’s also in the jsfiddle–well basic proof that access to the parent works reliably (we’d need our transpiler to add references to the parent for us if we cant figure out how to do it automatically in some React mixin or override). You can pass down a parent by reference. When a parent changes, you’re re-rendered anyway, you now have access to that parent and the new returns of its helpers. All automatically. Getting it to play nice with the pure render mixin we’ll save for another day, but can likely have a solution too–that is if it doesn’t just work like regular components. The point is that if the whole branch of the tree is re-rendered and you’re a child component in it you can just access state on a parent by reference, i.e. a reference to the parent, and then utilize a helper method on the parent, which then retrieves data from its own state, bringing it into the child component. We haven’t violated the laws of “unidirectionality”, only “immutability” --ever so slightly. I’m personally not opposed to breaking rules if it works–it’s how the web evolved to what it is and continues to evolve: the standardization of hacks that achieved majorly in-demand features when nothing else could. Tracker itself could be considered one such hack. Same with virtual dom. Each wasn’t the standard way of going about things prior to its existence. If we can achieve this in a 100% reliable fashion, we have the works for a better interface than React proper.


#13

would love that repro.


#14

here’s a precise example of the helper inheritance interface from a discussion with @mitar:


#16

@sashko @tmeasday render method based reactivity is done and the package is updated. The example app is also updated to show how these problems dont exist anymore:

git clone https://github.com/ultimatejs/tracker-react-todos-example.git
cd tracker-react-todos-example
meteor  

The example repo’s readme highlights how tracker-based reactivity plays nice with React’s state-based reactivity, thereby being the key mechanism that solves the issues discussed today minus the Tracker.fush() one:

  • @sashko’s outer scope reactive sources
  • @tmeasday’s helper methods being called with different arguments in React-triggered re-renders - no longer applicable
  • @tmeasday’s potentially incorrect methods becoming reactive - no longer applicable
  • @faceyspacey’s different code paths possibly not triggering certain helpers and render method not being made into a new autorun on React-triggered updates - was already solved if moved old reactive binding code just to render method

…It just keeps on getting easier and easier–the helper-based version was like half as much code as the original getMeteorData version, and this version is like half the code as the helper-based one. Now that the autorun re-binding is happening every time render methods are called, even if triggered by React renders (rather than only on componentWillMount like before) we are able to overlap perfectly with React-triggered state-based reactivity. I do wonder what the performance penalty is–if any–for constantly recreating our autoruns on every single component’s re-render.

As for the Tracker.flush() issue, it seems we first need a mechanism to synchronously flush React. Then we call both Tracker’s and React’s flush back to back:

Tracker.flush(); //trigger forced updates
React.flush(); //synchronously ensure all components are re-rendered
//execute code you usually would (with expectation that DOM is up to date)

Am I missing something?

The closest thing I can find available in scope is: React.addons.batchedUpdates(). But it seems we want ReactUpdates.flushBatchedUpdates() which isn’t exported for us. Theoretically we aren’t using jQuery or velocity or whatever for animations anymore, and are instead using the React animation addon or one of the better community animation packages; and instead of Tracker.afterFlush() we are using lifecycle hooks like componentDidUpdate–so we have no need for Tracker.flush/afterFlush() in order to manually manipulate the DOM. And of course we use things like refs to access form values in the DOM. Tracker.flush/afterFlush() may turn out to be a non-issue.


#17

Very pro-active. Thank you. It seems a great way to go. Reading your piece a few times, to get the state of mind we need to get back into full Meteor trust…


#18

That was long read :smiley:
Sometimes I think that observing DDP and maintaining 1 big immutable Atom kinda redux style replacing minimongo would solve many recomputing issues.
But who would sacrifice time to write that…
React could connect kinda natively as normaly in Redux and there could be some easier hacks to simulate normal cursor invalidation events.
But that is just my feeling.
Edit: And it is not minimongo, but whole collection handling in mongo package when I am now fast looking into source. Still it all use/call LocalCollection which is defined in minimongo. So probably replace it with other LocalCollection object which will be internally using redux store. That would be fun.

Good work anyway.


#19

This is very cool - I’ll definitely have to try using it ASAP!


#20

Do you still need this? It looks like you worked it out already…


#21

I don’t. …tho, I’m curious to what the issue was. React-triggered re-renders were re-creating the autorun based on the new arguments. Maybe I was missing something.