Best way to import Blaze templates into React

Continuing the discussion from React guide article, where I said:

I think the Using Blaze with React section should be renamed to Using React Components in Blaze and that we should have a corresponding Using Blaze Templates in React. Or something along those lines.

We’d like to establish the preferred way of doing this, and add it to the guide.

These are the options I’m aware of:

What are you using, why did you choose it over other solutions, and how has it worked out for you?

5 Likes

Regarding my gadicc:blaze-react-component, my motivations were as follows:

  • Best practices for Meteor 1.3 (don’t depend on meteor-react, import/export pattern, etc)
  • Single-step to use, no need to first convert the template in JS beforehand
  • Simple pattern that’s intuitively similar to react-template-helper.
  • Blaze component should be updated reactively, not recreated on prop change.

It looks like this:

import React from 'react';
import Blaze from 'meteor/gadicc:blaze-react-component';

const App = () => (
  <div>
    <Blaze template="itemsList" items={items} />
  </div>
);

The recommendation for react-template helper looks like this:

<template name="userDisplay">
  <div>{{> React component=UserAvatar userId=_id}}</div>
</template>

where the component is passed in via a helper.

2 Likes

Making a <BlazeComponent> for React can be fairly simple, if you want to just do it yourself without using a package:

import React from 'react'
import ReactDOM from 'react-dom'
import { ReactiveVar } from 'meteor/reactive-var'
import { Template } from 'meteor/templating'
import { Blaze } from 'meteor/blaze'

export default
class BlazeTemplate extends React.Component {
    render() { return <div ref="blazeContainer"></div> }

    componentDidMount() {
        const container = ReactDOM.findDOMNode(this.refs.blazeContainer)
        const {name, data} = this.props

        this.reactiveData = new ReactiveVar(data)
        this.componentWillReceiveProps(this.props)
        this.blazeView = Blaze.renderWithData(
            Template[name],
            () => this.reactiveData.get(),
            container
        )
    }

    componentWillUnmount() {
        Blaze.remove(this.blazeView)
    }

    componentWillReceiveProps(nextProps) {
        const {data} = nextProps
        this.reactiveData.set(data)
    }

    shouldComponentUpdate() { return false }
}
import BlazeTemplate from './BlazeTemplate.js'

class UsageExample extends React.Component {
    render() {
        const data = {one: 1, two: 2}
        return (
            <div>
              <h1>Blaze inside React:</h1>
              <BlazeTemplate name="someBlazeTemplate" data={data} />
            </div>
        )
    }
}
1 Like

Similarly, we can make one the other way around for use in Blaze:

<template name="ReactComponent">
  <div class="reactContainer">
  </div>
</template>
Template.ReactComponent.onRendered(function() {
  const reactClass = this.data.class
  delete this.data.class
  this.reactContainer = this.firstNode

  ReactDOM.render(
    React.createElement(reactClass, this.data),
    this.reactContainer
  )
})

Template.onDestroyed(function() {
  ReactDOM.unmountComponentAtNode(this.reactContainer)
})
<template name="UsageExample">
  <div>
    <h1>React inside Blaze:</h1>
    {{>ReactComponent class=someReactComponent otherProp="..."}}
  </div>
</template>

The above codes are untested, but that’s the rough idea. :blush:

1 Like

Thanks, @joe. What would you say are the advantages of writing these by hand rather than using a package? It seems like a lot of extra work? Also in terms of everyone needing to solve the same problems?

The only advantage is the satisfaction of having implemented it. :smile: But yeah, a package helps people all solve a problem the same with and improve it together. :]

1 Like

Well, there’s also this feeling of “owning my code” when I write something, as opposed to just using packages for everything, in which case I might not “own my code” and may feel less empowered when it comes to modifying things to be exactly how I want them. Of course, I could also read the code for some package, but sometimes just writing the code leads to a better and more interesting learning experience for me than reading.

Hmm, actually I wonder - would it be better to just list the code in the guide than recommend a specific package? What are the tradeoffs?

Anyway, of the options provided, looks like thereactivestack has the most popular one (maybe because it’s in their boilerplate app?), but the gwendall and gadicc ones have a similar design.

OTOH, it’s less that 50 lines of code in every one of the packages. So it seems a bit like bikeshedding to pick which one is the best since they probably do the same thing.

It seems like @gadicc yours is actually the best, because you handle the props and variable setting in the clearest way. Let’s leave this thread open for another day or so, and then recommend your package if nothing dramatic comes up.

Thanks. I felt like a slightly higher standard was needed in case it does go in the guide so I added some tests, CI and some initial code towards SSR. The latter is something useful that could come in via an update vs static code. I’m still interested to hear other opinions though.

Essentially all of these packages are out of date/deprecated/forgotten, so I wouldn’t bother recommending one.

1 Like

Yep - perhaps people can just copy the code from inside them.

Hey, this isn’t true. gadicc:blaze-react-component is still actively maintained. The issue in question (which was answered in 3 hours, I might add) was a result of using static-html instead of the templating package. In the newly released version, we clarify this use case both in the README and with a more helpful error message if the template is not found:

No Template["test1"] exists.  If this template originates in your app,
make sure you have the `templating` package installed (and not, for
e.g. `static-html`).

I still think it’s better to have a centrally maintained package, that addresses unanticipated edge cases and adds new features (e.g. SSR following progress on community Blaze work). As with all my projects, PRs are always welcome and I’d love for the package to be community maintained too.

6 Likes

Thanks @gadicc! Worked perfectly.

1 Like

The advantage to hand-rolling it in, is that you can begin/continue the process of re-engineering your other code style into the new code style. Eventually you could then in a future version disable the older compatibility layer.