Preview of official React support

Hi, I saw your thread over there. Let’s see what people say; if there is demand for more migration tools we can think about building them, but it looks like there are already some great community things about it, like the jsx-templating package here: https://atmospherejs.com/timbrandin/jsx-templating

I suspect the need for refactoring between different view layers will be very application or situation specific, so it might make sense to have people build their own tools for that.

What’s the difference between this and reactjs:react? I’ve just started using the latter with Webpack to integrate React, and nothing seems to be lacking yet.

How exactly do you mean about server-side data? Data from the server side (or something derived from it) pretty much has to go in the state of some component, even if that’s a controller-view that passes things from its state down via props.

I looked at the tutorials on this, I have to say I frankly don’t understand some things. I like how reactjs:react puts getMeteorState() in this.state because then you can track that with the lifecycle methods like componentWillUpdate(), shouldComponentUpdate(), etc. Why this package puts things in this.data instead (and calls forceUpdate() I assume?), I don’t understand. I’m sorry, I’m going to keep promoting reactjs:react unless I can see some kind of advantage to this package.

I’ve put the reactjs:react mixin into a setState infinite loop in certain edge cases. this.data eliminates that.

Using this.state may seem like a great idea but ideally you want your data coming from props. You should avoid this.state whenever possible (many times it’s not).

The best pattern with Meteor so far is to use the container pattern. Your FeedListContainer handles the subscription and mixin, sideloading the data from Meteor. It passes this.data into it’s only component FeedList as props. The container only has one job, gather data and push it down via props.

The FeedList component now knows nothing about how it’s getting it’s data. It’s basically a pure function that has params (props). It’s now very re-useable and easy to test (it just takes in props). FeedList can implement shouldComponentUpdate to cancel rendering on children.

FeedListContainer = React.createClass({
  mixins: [ReactMeteorData],

  getMeteorData: function() {
    var sub = Meteor.subscribe("feed");

    return {
      feedReady: sub.ready(),
      postItems: Posts.find({}, {sort: {createdAt: -1}}).fetch(),
    };
  },

  render() {
    return (
      <FeedList
        isReady={this.data.feedReady},
        postItems={this.data.postItems}
      />
    );
  }
});

and then the feed list…

FeedList = React.createClass({
  propTypes: {
    postItems: React.PropTypes.object,
    isReady: React.PropTypes.bool,
  },

  render() {
    if (!this.props.isReady) {
      return <LoadingSpinner />
    }

    return (
      <div className='FeedList-container'>
        {
          this.props.map(function(post) {
            return <Post postData={post} />
          })
        }
      </div>
    );
  }
});

[quote="jedwards, post:64, topic:6150"] How exactly do you mean about server-side data? [/quote]

I think @sashko was referring to Flux users who are loading serverside data are not using this.state in their component. Instead the component merely triggers an action (say and action called PRESSED_LOAD_MORE) and loads in data from the server. This data is stored in a Flux store (global state for a domain). The component just requests state from the Flux store on render and never touches setState (you could use setState to load the Flux data but you don’t have to).

this.state should really only (ideally) be used to keep track of transient state of a component… say which tab is open in a tab list, or what photo a gallery is indexed at… not the feed of post data. You can do this but it doesn’t scale well.

5 Likes

Hey, I think it’s totally legitimate to want that stuff in this.state. Before you start using reactjs:react again, let me suggest an alternative:

  1. Use the react-runtime package. This is the package that all Meteor packages and apps that use React should start depending on, so that you don’t end up shipping multiple versions of the React library. This package includes no mixins or anything else.
  2. Use the jsx package. We have put a lot more effort into making it stable on all platforms, and it will be maintained as part of Meteor core moving forward.
  3. Copy the mixin logic from reactjs:react into a new package - you could call it jedwards:get-meteor-state. Now, you can use the pattern you like.

With this approach, you will get all of the benefits of using mostly core Meteor packages which are guaranteed to be maintained into the far future, while not having to use react-meteor-data which you don’t like.

This is the reason we have published all of the parts of react separately - exactly so that you can pick or choose the parts you like.

4 Likes

Were the setState infinite loops triggered by the mixin itself or was your code doing Meteor work in shouldComponentUpdate, componentWillUpdate, or componentDidUpdate that inadvertently triggered a call to getMeteorState? I could imagine that if you need to respond to changes in transient state caused by the user, your code would accidentally get triggered by the getMeteorState changes as well…

Not all websites are social media feed lists. If that’s all you’ve worked on you might get used to some patterns that work well, but they don’t necessarily work well for other kinds of websites (for instance, I’ve used setState() with Immutables to improve performance in an interactive dashboard layout).

From the React website itself: setState(function|object nextState[, function callback])
“Merges nextState with the current state. This is the primary method you use to trigger UI updates from event handlers and server request callbacks.

And I know about this container pattern (React actually calls it the controller-view pattern) and use it often. But still, my controller-views are often using setState and passing down props from this.state instead of using forceUpdate or React.render.

If Flux patterns shun this dictum from the horse’s mouth, how to do they trigger UI updates? forceUpdate or React.render?

1 Like

My hesitation to use the jsx package is that I don’t like dealing with the package global vars and script load order in idiomatic meteor…or does the jsx package allow ES6 import?

I was talking about it as an alternative to reactjs:react which also doesn’t have support for modules.

Probably the latter… to be honest I can’t remember the exact details.


[quote="jedwards, post:68, topic:6150"] Not all websites are social media feed lists. If that's all you've worked on you might get used to some patterns that work well, but they don't necessarily work well for other kinds of websites (for instance, I've used setState() with Immutables to improve performance in an interactive dashboard layout). [/quote]

I think it would still work well with that kind of app though? I’ve used it in a dashboard interface with lots of widgets. However I think that the extra layer is a bit cumbersome though.


Sure. After re-reading my post I didn’t mean to come across as anti-state. What I meant is the state is stored in the store, not the component. To be honest I haven’t looked too hard into the inner workings of the different flux implementations but some that i’ve seen use setState and others forceRender after re-fetching (Alt uses getInitialState and returns the store typically… not too familiar with others).

I’ve been wanting to tinker with using an immutable lib with Meteor and a Flux lib and somehow get data from the subscription in a store and then save into the immutable when the data changes… However I haven’t got any farther than that. With the latency compensation it might be fairly easy to do this in the store (as opposed to async) or even a utils folder.

Sorry, it’s just the typical anxiety I have these days of “what? the way I’m doing things is bad practice?”

Immutable is kind of cool, but it’s a bit cumbersome to use, so I only use it when the performance benefits outweigh the cumbersomeness, though I’ve also used it at times to avoid needing to return a copy of the data from the stores (when not using Meteor, that is)

1 Like

@sashko @avital I’m not sure why I get this error:

Error: In template "board", call to `{{> React ... }}` missing `component` argument.

My code looks like this:

JavaScript:


MyComponent = React.createClass({
    mixins: [ReactMeteorData],
    render() {
        return (
            <div className={'famous-board-container '+this.props.board._id}></div>
        )
    },
    onComponentDidMount() {
        console.log('Mounted a React component.')
    }
})

HTML:

      {{> React component=MyComponent board=this }}

Ah, well, I found the workaround:

Template.blazeTemplateThatWillContainReact.onRendered(() => {
    React.render(MyComponent, this.$('.targetElement')[0])  
})

You need to pass in the component with a helper.

Ah, indeed that worked.

Template.board.helpers({
    MyComponent: () => MyComponent
});

By the way, @sashko (and @seanh and @jedwards because you guys were wondering about modules). I’m close to releasing rocket:module which will let us use ES6/AMD/CJS modules in apps and packages. It will also share dependencies/modules across packages. Once I release (aiming for end of this month before DevShop) it’d be cool to get react using rocket:module in place of cosmos:browserify, so that those dependencies can be shared with other packages.

1 Like

Cool! I had seen that and I’m glad to hear someone’s working on it. Webpack has enough other advantages that I’ll probably keep using it though…

@jedwards Rocket:module is using Webpack behind the scenes. :smiley: Let me know if there’s anything specific you’re doing with Webpack that might be something we can accommodate in rocket:module.

Oh! Is it running a webpack-dev-server? I like using react-hot-loader, sass-loader, and url-loader. I also had issues with google-map-react loading two copies of React that PrefetchPlugin somehow fixed (I still haven’t gotten to the bottom of that). And I figure who knows, the code splitting could come in handy someday.

So I’m curious how you’re using it exactly. I would have thought that a thin wrapper around webpack, exposing all webpack features, would have been easier than something that only exposes some. I’m also curious how you managed to get source maps from webpack into Meteor, because when I tried to make a package to pull in the webpack source map, Meteor crashed complaining that some things in the source map weren’t in the source.