What's so cool about React? Am I obsoleting myself by not learning it?

Wouldn’t you just handle the radio button change with a function in the React component that used setState on a variable that could be used to hide or show a form?

This might not be a very important concern for people reading meteor forums, but: React is more ubiquitous. You can use it with Meteor. And with Rails. And with .NET. And with any other backend. Whereas with Blaze… I hadn’t even heard about Blaze before trying Meteor, and I try my best to keep up with the industry.

This also has a benefit of more experience being out there. For any given problem, there have been more people solving it with React than Blaze. More people have given thought to structure and best practices. And maybe even released the solution as a library you can re-use.

And in the end, if Meteor does not work out for you, it’s easier to migrate a React frontend to something else.

2 Likes

The only reason I’m not using react in my current project is because it is stated that “React router APIs will be totally different in version 1” and I don’t want to rewrite things.

If only I had a rough idea of when it’s released…

react-router has a release candidate and should be fairly stable as far as the API. If you’re not planning on launching very soon I would use that instead. FlowRouter works too but doesn’t have nested UIs.

I’m personally migrating one app to 1.0-RC very soon as it has a lot of nested UI.

The new 1.0 has an easier Link API which should make it much easier to migrate older apps:


// v0.13.x
<Link to="about">About</Link>

// v1.0
<Link to="/about" activeClassName="active">About</Link>
1 Like

This is out of topic, but do you know if it’s possible to pass properties directly on the route in 1.0? Like <Route component={MyComponent} components-data={data}/> ?

I believe so. If not I know you can wrap it like this:

<YourDataComponent data={data}>
    <Router component={MyComponent} components-data={data}>
        <Route foo={} bar={} />
        <Route foo={} bar={} />
    </Router>
</YourDataComponent>

As that’s how the Redux does it so you’re only passing it in once. However I bet you’ll be able to pass it into each individual route if that’s preferred.

With FlowRouter you need to do it for each one so I made a helper to do that:
Use Functional Programming to Simplify Your Meteor Code

1 Like

Is it possible to use React Router without using webpack/browserify and using require statements? Call me strange, but I’m not a fan of going that route, it feels very “un-Meteor” and cluttery to me.

Check out this official React-Todos example: https://github.com/meteor/react-packages/blob/devel/examples/react-todos/client/routes.jsx

Pretty simple!

1 Like

I love this aspect of React and I think it’s been very helpful for app development.

That said, I’d like to point out that, so far at least, these architecture trends have been influenced by the fact that many web apps are much simpler than desktop apps. They do work great for the typical web apps of today. If on the other hand I was trying to design an intense performance critical app, like a video game or CAD software for example, I’m not sure I would take the monolithic store approach where every change propagates all the way through the state hierarchy.

Redux tends to advocate passing actions through a wide variety of handlers, whether or not they are relevant to that particular action, for the sake of simplicity and robustness. This is fine for many apps but it means that the more elements you add to your state tree, the more work it’s doing each time. And it might still be a negligible amount of work, but in my app there can be many actions a second when the user is dragging things around, so I chose to narrow down my event handlers by key. Even if performance is still acceptable, consuming less battery is also desirable these days.

I met one developer working for a company implementing Adobe InDesign-like software for the web using Backbone, mustache, and HTML canvas, I don’t know what else. For all I know that could offer them the best performance.

All design decisions have tradeoffs, so I think it’s important to keep an open mind.

1 Like

Ahh. This is what I’m talking about:

client/lib/app.browserify.js

ReactRouter = require("react-router");

Doing it this way seems hacky to me, like using duct tape to piece something together. IMO it would be much better to be able to run meteor add react-router and then be done with it, and have immediate access to ReactRouter.

I just don’t like the idea of using webpack or browserify in Meteor. It feels like I’m trying to shoehorn something in that doesn’t belong.

2 Likes

Sorry if I’m taking this out of context (I haven’t had time to go through the whole thread yet), but I wanted to point out one type of people for who decoupling templates from scripts is very useful: non-developers.

With Blaze, you can have a front-end designer take care of the whole HTML/CSS part of your app without having to touch the actually JavaScript code once, even if they’ve never laid eyes on Meteor before.Handlebars/Spacebars takes literally 5 minutes to learn. I’m not so sure if that’s possible with React?

Obviously this is very important for me because of Telescope (I want to make it super-easy for people to theme and customize their apps), but I think it’s a valid concern generally, too.

3 Likes

There is a react-router package but it just wraps the one on NPM and handles browserify behind the scenes. The problem is that these modern libraries use CommonJS / ES6 modules to export and it’s hard to pull into a Meteor package as is. I’m hoping ES6

Using webpack with Meteor is definitely a shoehorn but I like to think of it the other way… as in i’m building my app the ‘normal way’ and adding in a few global Meteor helper functions to save time with auth/realtime/ :smile:

I’m hoping MDG’s next release (after 1.2) will have modules so you can just import it from NPM in a non hacky way :smiley:

Yep that’s a valid point! I feel like the designers who can use HTML/CSS could get acclimated if they’re using JSX (the non JSX… functional method would not be good for them).

It’s definitely a bit of a ramp up because there’s JS lurking above the render method. However I don’t think it’s a deal breaker. Designers are really good at breaking up UI into components so I think that separate might be 2nd nature? What’s your opinion?

For example if you structure your JSX so that it’s readable and broken down (not 100 lines) here’s a bit that has some conditional logic.


this.FeedItemHeader = React.createClass({
  mixins: [TimeFormatMixins],
  propTypes: {
    userName: React.PropTypes.string,
    ownerId: React.PropTypes.string,
    destroyPost: React.PropTypes.func,
    createdAt: React.PropTypes.instanceOf(Date),
  },

  formatDate() {
    var date = this.props.createdAt;
    return date && this.fromNow(date);
  },

  handleClick() {
    PostActions.deletePost(this.props._id);
  },

  render() {
    var needsDeleteBtn = this.props.ownerId === User.id();
    return (
      <div className="feed-item__header">
        <div className="avatar" />

        <div className='name-date'>
          <div className="name">{this.props.userName}</div>
          <div className="date">{this.formatDate()}</div>
        </div>

        {needsDeleteBtn &&
          <div className="destroy" onClick={ this.handleClick }>
              Delete Post
          </div>
        }
      </div>
    );
  }
});

Some people make the argument that it’s easier to onboard devs without React but honestly for a developer (not designer) it should only take 1 day of hands on training to get them up to speed. To me learning Blazes extra syntax and Reactive quirks takes much longer than learning React.

2 Likes

Well I know a lot of us haven’t been doing it that way…we just do

import ReactRouter from 'react-router';

And it’s only in the scope of that module. I haven’t run into any situation where I needed to use globals to make stuff from my webpack bundles available to any Meteor code outside of them.

Actually this seems a bit deceptive to me. Typically with React when you change one little thing you end up re-rendering virtual DOM for a whole entire view (or if you need better performance, at the very least checking which components in that view need to be re-rendered). Obviously this is more work but it’s very unlikely that you’ll fail to update something and leave the view in an inconsistent state.

Whereas with Blaze, as far as I assume, if say one element of a collection changes, it only triggers a re-render on the specific template element that’s displaying that element, right? To me this is exactly like the Backbone/jQuery way of doing things except that it handles all the eventing for you, so mistakes are much less likely. And I’m also assuming Blaze can perform better than idiomatic React in some situations.

Interestingly, I’ve seen various discussions in the React repo about implementing “sideways data loading”, which basically just means passing some kind of observable object into a React Component and automatically re-rendering when it fires an update. It’s similar to using ReactMeteorData, and kind of a half-way point between typical React and Blaze, where many levels of the app handle their own re-rendering separately instead of being like “okay entire view hierarchy, here is your entire new state hierarchy – render it!”

As far as what I like about React:

The pure ultra genius of JSX is eliminating scope confusion. There’s no more hunting through Angular scripts to see if something is somewhere in the $scope hierarchy, or in Meteor jumping to your template helper file to see what your template is actually referring to. When you create a JSX element, anything in the JS scope at that point is fair game to use in your JSX. There’s no headache at all.

The other huge benefit of React, similar to web components, but perhaps even more easy to use, is flexibility and code reuse. This is because you can create and pass JSX elements around effortlessly. For instance if you want to display a variety of different toast messages at the bottom of the screen, you could just fire off a toast event containing the JSX element you want to display as a toast – and voila, now you can make any type of element you want show up as a toast. Currently this would be a bit more annoying to do with web components because if you want to create an element and render it later, you’d have to do a document.createElement(...) and a bunch of appendChild calls if you want anything inside of it. Though you could just use React to render web elements instead :slight_smile:

[quote=“jedwards, post:73, topic:8100, full:true”]
Typically with React when you change one little thing you end up re-rendering virtual DOM for a whole entire view[/quote]

As far as I’m aware, React only renders components whose state or props have changed, it definitely doesn’t re-render the entire view. So in essence, it works just the same as Blaze.

@sashko Everywhere I go I seem to read about your fondness of react lately. I’m trying to get into it myself but I’m finding myself missing stuff like autoform / simple schema, or useraccounts:core. I’m curious, how do you approach forms, validation and login when working with react? Have you developed your own components or perhaps you’re using blaze stuff within react too? I’d be interested to find out at least a good solution/approach to forms/validation. I’m currently writing my own components for login. I suppose it’s still early days and we might see react specific meteor components after 1.2 is actually released, but I’m eager to begin now.

The problem with this issue is how we can only provide templates without other functions like actions(click) and so on.
Even someone who knows nothing about JS (or at least React) should be able to change these.

That’s a kind a issue here. Hope every designer know React in few years from now (or someone will find a cure)

They do the same thing but in different ways. If the contents of a label changes they both update only the contents of the label, not the entire page. React diffs and updates while Blaze updates directly. At the end of the day you take a React code and compare it with the Blaze equivalent and it’s almost a matter of rearranging the code. You still have the same pieces though.

@manuel @ffxsam I didn’t explain myself well, I’m trying to elucidate the subtle details. There seems to be a tendency these days to assume that it’s not worth worrying about performance; but I haven’t seen many complex desktop apps ported to web pages yet, I think someday they will, and I think they might run into performance problems if using the monolithic state tree approach. If that turns out to be wrong, well, it’ll be a huge win for us programmers :slight_smile: But in any case, knowing the internal details of these frameworks regarding performance or otherwise can never hurt. So to get into details:

The word ‘render’ is ambiguous here. Let’s say you have a component whose render() method returns a <ul> containing 100 <li>s rendered from an array in props. Then you copy that array, change just one element, and pass it into to the component. Its render() runs again and generates the 100 React elements (just the temporary representations I mean) for the <li>s. It then compares all 100 of those to their counterparts in the virtual DOM, finds only one has changed and updates the one <li> in the real DOM corresponding to it. So it’s doing extra work even though it’s only changing one element in the real DOM. Or in other words, the amount of work done could be considered O(n) even if only one item is changed.

Likewise if the 100 children were React pure render components it would still do some extra work calling shouldComponentUpdate() on each of the 100, though only one would return true and have its render() method run and React element compared with the virtual DOM.

If the children were instead sideways data loaders listening to individual ReactiveVars or something like them, when one of those changed, only the corresponding child would be notified and rerender itself; no computation would be done for the other 99.

I would hope that Blaze can similarly process its templates such that if 1 of 100 Mongo items for <li>s changes, it updates only the corresponding <li>, without doing any processing at all for the other 99, not even to check if they need updating. Or am I wrong? Does it simply reprocess the entire template each time any of its data changed?

In theory the template compiler could create a reactive computation for each of the <li>s so that only the one whose data changed reruns.

Virtual DOM diff and shouldComponentUpdate() are what enable you to pass in a changed immutable representing your application’s entire state tree, and get fast enough updates – in most use cases. In cases it works well enough for, you can write significantly simpler, clearer code. But if I had to write an extremely demanding realtime app, I would probably go with fine-grained change events and sideways data loading instead of a monolithic state tree.

Does this make sense?

1 Like