Hi, I was working on some updates/upgrades to some of our apps and would like to do it with React. Also I looked for the minimal effort to just replace the “hurting” parts but do not replace the whole app.
Setup of the existing app was:
- Meteor 1.1.0.2
- FlowRouter
- FlowLayout
- Materialize-SASS
First of all I migrated to Meteor 1.2.0.2, updated the packages and add the React ones
New Setup for app without any changes on sources
- Meteor 1.2.0.2
- FlowRouter
- BlazeLayout
- React
- React-Template-Helper
- ReactLayout
- Materialize-SASS
So far - so easy. I will proceed my explanation with just a small welcome app in mind with 3 pages
- / = Welcome
- /about = About Page
- /imprint = Imprint Page
Currently all pages are done with Blaze, so my app looks like:
- head.html
- router.js
- layout.html
- sidebar.html
- welcome.html
- about.html
- imprint.html
The routes at routes.js
are looking like:
FlowRouter.route('/', {
action: function(params) {
BlazeLayout.render('appLayout', {page: 'pageWelcome', app_data: { title: 'Hello World'} });
}
});
The sample layout.html
is defined as:
<template name="appLayout">
{{> appSidebar}}
<div class="page-main">
{{> Template.dynamic template=page}}
</div>
</template>
and my welcome.html
is just simple:
<template name="pageWelcome">
<div class="page-welcome">
<h1>{{app_data.title}}</h1>
<p>Hello world!<p>
</div>
</template>
First Goal:
Replace the about.html|.js
with React as about.jsx
:
PageAbout = React.createClass({
render() {
return (
<div className="page-about">
<h1>{this.props.app_data.title}</h1>
<p>React about page!</p>
</div>
);
}
});
Minimal change for layout.html
Well that’s easy - now how to call? I do not want to replace my complete layout, so I just changed this a bit and use the function from package react-template-helper
to insert React component into Blaze views:
<template name="appLayout">
{{> appSidebar}}
<div class="page-main">
{{#if hasReactComponent}}
{{> React component=reactComponent app_data=app_data}}
{{else}}
{{> Template.dynamic template=page}}
{{/if}}
</div>
</template>
So I defined just one clause to switched between Blaze and React rendering. All I need to do finally, was to change the action on FlowRoute:
FlowRouter.route('/about/', {
reactComponent: function() { return PageAbout; },
action: function(params) {
BlazeLayout.render('appLayout', {app_data: { title: 'Hello World'} });
}
});
To get this altogether we need two small template helpers at layout.js
:
Template.appLayout.helpers({
hasReactComponent: function() {
return !_.isUndefined(FlowRouter.current().route.options.reactComponent);
},
reactComponent: function() {
return FlowRouter.current().route.options.reactComponent();
}
});
That’s it - I just exchanged a very small part of my app.
Next goal
In case that all from previos was smoothy, I wished to replace also some more functional part of my app with some new React components. Therefor I cannot use my main layout.html
anymore but need to run ReactLayout
.
So I changed the extension to router.jsx
and created that new route first:
FlowRouter.route('/blog/', {
action: function(params) {
ReactLayout.render(AppLayoutReact, {content: <PageBlog />, app_data: { title: 'Blog Posts' } });
}
});
and follow up with the new React component layout_react.jsx
:
AppLayoutReact = React.createClass({
render() {
return (
<div>
<div className="page-main">
{this.props.content}
</div>
</div>
);
}
});
Well so long … easy again BUT … what about my sidebar.html
Inside the new React layout I have to rebuild my sidebar
content but won’t double my sources.
For that I created a new package and add that to my app:
That allows to use Blaze templates as React components. My layout_react.jsx
:
AppLayoutReact = React.createClass({
render() {
return (
<div>
<React.BlazeView template="appSidebar" />
<div className="page-main">
{this.props.content}
</div>
</div>
);
}
});
Wow! Amazing! - I am impressed how easy to mix the elements
Big thanks to MDG for that nifty meteor and @arunoda and his team for those great packages
Cheers
Tom